Below is a translation of one part of the Rust Crash Course article series by Michael Snoiman, which focuses on parameter passing mechanisms, iterators and closures regarding how ownership is transferred, and relates to mutability and lifetimes.
I also tried to translate as close to the author's style as possible, but reduced a few interdomes and exclamations that are not very significant for the meaning.
Parameter types
First, I want to deal with a possible misconception. This could be one of those "my brain was damaged by Haskell" delusions that imperative people don't face, so I apologize in advance for my jokes on myself and other Haskellists.
Do the type signatures of the two functions match?
fn foo(mut person: Person) { unimplemented!() }
fn bar(person: Person ) { unimplemented!() }
: " !". , (exactly the same). (inner mutability) person
, . person
, . : , foo
:
fn main() {
let alice = Person { name: String::from("Alice"), age: 30 };
foo(alice); // !
}
:
fn baz(person: &Person) { unimplemented!() }
fn bin(person: &mut Person) { unimplemented!() }
-, , baz
, bin
foo
. Person
, Person
. baz
bin
? ? , foo
bar
, , mut
β . !
:
fn main() {
let mut alice = Person { name: String::from("Alice"), age: 30 };
baz(&alice); //
bin(&alice); // !
bin(&mut alice); //
}
bin
, bin
, . . , : , , ( 2).
, :
- ( )
foo
- ,
baz
- ,
bin
, , , , , . (. , , ; foo
, baz
bin
person
).
vs.
. , ? ! birthday
, - 1.
#[derive(Debug)]
struct Person {
name: String,
age: u32,
}
fn birthday_immutable(person: Person) -> Person {
Person {
name: person.name,
age: person.age + 1,
}
}
fn birthday_mutable(mut person: Person) -> Person {
person.age += 1;
person
}
fn main() {
let alice1 = Person { name: String::from("Alice"), age: 30 };
println!("Alice 1: {:?}", alice1);
let alice2 = birthday_immutable(alice1);
println!("Alice 2: {:?}", alice2);
let alice3 = birthday_mutable(alice2);
println!("Alice 3: {:?}", alice3);
}
:
-
_immutable
,Person
,Person
. Rust, , . - , , .
-
alice1
alice2
main
, (move) . alice2
β , , .
vs.
, Rust: β (it's unusual). , . , mut
.
, : , ('
) (lifetime parameters), , . , " ". . , Rust Book.
, , , , .
#[derive(Debug)]
struct Person {
name: String,
age: u32,
}
fn birthday_immutable(person: &mut Person) {
person.age += 1;
}
fn birthday_mutable<'a>(mut person: &'a mut Person, replacement: &'a mut Person) {
person = replacement;
person.age += 1;
}
fn main() {
let mut alice = Person { name: String::from("Alice"), age: 30 };
let mut bob = Person { name: String::from("Bob"), age: 20 };
println!("Alice 1: {:?}, Bob 1: {:?}", alice, bob);
birthday_immutable(&mut alice);
println!("Alice 2: {:?}, Bob 2: {:?}", alice, bob);
birthday_mutable(&mut alice, &mut bob);
println!("Alice 3: {:?}, Bob 3: {:?}", alice, bob);
}
// does not compile
fn birthday_immutable_broken<'a>(person: &'a mut Person, replacement: &'a mut Person) {
person = replacement;
person.age += 1;
}
birtday_immutable
. , . , . : , , (: person
. , , ).
birthday_mutable
β , . : person
replacement
. , person
. , β (person = replacement
). , person
, , . , , , , person
:
warning: value passed to `person` is never read
, main
bob
alice
. ? , . , main
, .
, birthday_immutable_broken
. , . , person
, .
: , , , .
vs.
, , . , , . , , .
:
fn needs_mutable(x: &mut u32) {
*x *= 2;
}
fn needs_immutable(x: &u32) {
println!("{}", x);
}
fn main() {
let mut x: u32 = 5;
let y: &mut u32 = &mut x;
needs_immutable(y);
needs_mutable(y);
needs_immutable(y);
}
, , , . y
&mut u32
, needs_immutable
, &u32
. , .
: , , , , ( , ).
:
, . , , . , . , , , . , , .
1
, 10. .
fn double(mut x: u32) {
x *= 2;
}
fn main() {
let x = 5;
double(x);
println!("{}", x);
}
: , (asterisk, *
) , (dereference) (. β β , , ).
//
fn double(x: &mut u32) {
//
// ,
*x *= 2;
}
fn main() {
//
let mut x = 5;
//
double(&mut x);
println!("{}", x);
}
?
fn main() {
let nums = vec![1, 2, 3, 4, 5];
for i in nums {
println!("{}", i);
}
}
, 1 5. ?
fn main() {
for i in 1..3 {
let nums = vec![1, 2, 3, 4, 5];
for j in nums {
println!("{},{}", i, j);
}
}
}
1,1
, 1,2
, ..., 2,1
, ..., 2,5
. - . nums
. ?
fn main() {
let nums = vec![1, 2, 3, 4, 5];
for i in 1..3 {
for j in nums {
println!("{},{}", i, j);
}
}
}
. .
error[E0382]: use of moved value: `nums` --> main.rs:4:18 | 4 | for j in nums { | ^^^^ value moved here in previous iteration of loop | = note: move occurs because `nums` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait error: aborting due to previous error
. , , (move) nums
. , , nums
. .
, nums
for
. , . . , nums
. ()!
nums
, (borrowing)? , !
fn main() {
let nums = vec![1, 2, 3, 4, 5];
for i in 1..3 {
for j in &nums {
println!("{},{}", i, j);
}
}
}
, : j
? . println!
, :
let _: u32 = j;
error[E0308]: mismatched types --> src/main.rs:5:26 | 5 | let _: u32 = j; | --- ^ | | | | | expected `u32`, found `&{integer}` | | help: consider dereferencing the borrow: `*j` | expected due to this
, :
let _: &u32 = j;
nums
, , . " " ? !
fn main() {
let nums = vec![1, 2, 3, 4, 5];
for i in 1..3 {
for j in &mut nums {
let _: &mut u32 = j;
println!("{},{}", i, j);
*j *= 2;
}
}
}
. . . , , .
fn main() {
// nums
let mut nums = vec![1, 2, 3, 4, 5];
for i in 1..3 {
for j in &mut nums {
let _: &mut u32 = j;
println!("{},{}", i, j);
*j *= 2;
}
}
}
, . , , .
vec
, . ,
for j in &mut nums {
```Rust
```Rust
for j in nums.iter_mut() {
:
pub fn iter_mut(&mut self) -> IterMut<T>
iter()
, :
fn main() {
let nums = vec![1, 2, 3, 4, 5];
for i in 1..3 {
for j in nums.iter() {
let _: &u32 = j;
println!("{}, {}", i, j);
}
}
}
? into_iter()
. , (into) , ( , nums
Vec
). . , let nums
:
fn main() {
let nums = vec![1, 2, 3, 4, 5];
for i in 1..3 {
for j in nums.into_iter() {
println!("{}, {}", i, j);
}
}
}
fn main() {
for i in 1..3 {
// nums into_iter()
//
let nums = vec![1, 2, 3, 4, 5];
for j in nums.into_iter() {
println!("{}, {}", i, j);
}
}
}
for
, . for
, . into_iter()
, IntoIterator
. for x in y
, into_iter()
y
. , Iterator
.
2
, IntoIterator
InfiniteUnit
. Iterator
! , . ( : , ).
struct InfiniteUnit;
fn main() {
let mut count = 0;
for _ in InfiniteUnit {
count += 1;
println!("count == {}", count);
if count >= 5 {
break;
}
}
}
struct InfiniteUnit;
impl IntoIterator for InfiniteUnit {
type Item = ();
type IntoIter = InfiniteUnitIter;
fn into_iter(self) -> Self::IntoIter {
InfiniteUnitIter
}
}
struct InfiniteUnitIter;
impl Iterator for InfiniteUnitIter {
type Item = ();
fn next(&mut self) -> Option<()> {
Some(())
}
}
fn main() {
let mut count = 0;
for _ in InfiniteUnit {
count += 1;
println!("count == {}", count);
if count >= 5 {
break;
}
}
}
, .. repeat
, . .
struct InfiniteUnit;
impl IntoIterator for InfiniteUnit {
type Item = ();
type IntoIter = std::iter::Repeat<()>;
fn into_iter(self) -> Self::IntoIter {
std::iter::repeat(())
}
}
fn main() {
let mut count = 0;
for _ in InfiniteUnit {
count += 1;
println!("count == {}", count);
if count >= 5 {
break;
}
}
}
, (flavors), :
into_iter
β ,iter
βiter_mut()
β
iter_mut()
, .
, . , (local scope). .
: , , , . , , , . , . , , , JS.
. , ?
fn main() {
fn say_hi() {
let msg: &str = "Hi!";
println!("{}", msg);
};
say_hi();
say_hi();
}
. :
fn main() {
let msg: &str = "Hi!";
fn say_hi() {
println!("{}", msg);
};
say_hi();
say_hi();
}
, :
error[E0434]: can't capture dynamic environment in a fn item --> main.rs:4:24 | 4 | println!("{}", msg); | ^^^ | = help: use the `|| { ... }` closure form instead error: aborting due to previous error
, : . :
fn main() {
let msg: &str = "Hi!";
let say_hi = || {
println!("{}", msg);
};
say_hi();
say_hi();
}
( ||
), . .
: let say_hi = || println!("{}", msg);
, .
3
, say_hi
: msg
. fn
.
:
fn main() {
let msg: &str = "Hi!";
let say_hi = |msg| println!("{}", msg);
say_hi(msg);
say_hi(msg);
}
:
fn main() {
let msg: &str = "Hi!";
fn say_hi(msg: &str) {
println!("{}", msg);
}
say_hi(msg);
say_hi(msg);
}
, say_hi
.
say_hi
? , : , . , , u32
, :
fn main() {
let msg: &str = "Hi!";
let say_hi: u32 = |msg| println!("{}", msg);
}
:
error[E0308]: mismatched types --> src/main.rs:3:23 | 3 | let say_hi: u32 = |msg| println!("{}", msg); | --- ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found closure | | | expected due to this | = note: expected type `u32` found closure `[closure@src/main.rs:3:23: 3:48]`
[closure@main.rs:3:23: 3:48]
β¦ , :
fn main() {
let msg: &str = "Hi!";
let say_hi: [closure@main.rs:3:23: 3:48] = |msg| println!("{}", msg);
}
:
error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `@` --> src/main.rs:3:25 | 3 | let say_hi: [closure@main.rs:3:23: 3:48] = |msg| println!("{}", msg); | ------ ^ expected one of 7 possible tokens | | | while parsing the type for `say_hi`
. ?
. . . , ? , :
fn main() {
let say_message = |msg: &str| println!("{}", msg);
call_with_hi(say_message);
call_with_hi(say_message);
}
fn call_with_hi<F>(f: F) {
f("Hi!");
}
msg
. , -, , . . , .
F
, . F
, . , :
error[E0618]: expected function, found `F` --> src/main.rs:8:5 | 7 | fn call_with_hi<F>(f: F) { | - `F` defined here 8 | f("Hi!"); | ^------- | | | call expression requires function
: , F
. - , : Fn
!
fn call_with_hi<F>(f: F)
where F: Fn(&str) -> ()
{
f("Hi!");
}
F
, , &str
, . , -, .
fn call_with_hi<F>(f: F)
where F: Fn(&str)
{
f("Hi!");
}
, Fn
, .
4
say_message
main
, .
fn main() {
call_with_hi(say_message);
call_with_hi(say_message);
}
fn say_message(msg: &str) {
println!("{}", msg);
}
fn call_with_hi<F>(f: F)
where F: Fn(&str)
{
f("Hi!");
}
say_message
, . .
fn main() {
let name = String::from("Alice");
let say_something = |msg: &str| println!("{}, {}", msg, name);
call_with_hi(say_something);
call_with_hi(say_something);
call_with_bye(say_something);
call_with_bye(say_something);
}
fn call_with_hi<F>(f: F)
where F: Fn(&str)
{
f("Hi");
}
fn call_with_bye<F>(f: F)
where F: Fn(&str)
{
f("Bye");
}
-? !
fn main() {
let mut count = 0;
for _ in 1..6 {
count += 1;
println!("You are visitor #{}", count);
}
}
, ! .
fn main() {
let mut count = 0;
let visit = || {
count += 1;
println!("You are visitor #{}", count);
};
for _ in 1..6 {
visit();
}
}
:
error[E0596]: cannot borrow `visit` as mutable, as it is not declared as mutable --> src/main.rs:9:9 | 3 | let visit = || { | ----- help: consider changing this to be mutable: `mut visit` ... 9 | visit(); | ^^^^^ cannot borrow as mutable
β¦ ? , . , . - . ?
: visit
(captured) count
. , visit
count
. . ? ? , , :
fn main() {
let mut count = 0;
let visit = || {
count += 1;
println!("You are visitor #{}", count);
};
call_five_times(visit);
}
fn call_five_times<F>(f: F)
where F: Fn()
{
for _ in 1..6 {
f();
}
}
:
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
! : , (Fn
), , (FnMut
). Fn
FnMut
where
. :
error[E0596]: cannot borrow immutable argument `f` as mutable --> main.rs:16:9 | 11 | fn call_five_times<F>(f: F) | - help: make this binding mutable: `mut f` ... 16 | f(); | ^ cannot borrow mutably
, . mut
f: F
.
?
Fn
FnMut
?
|| println!("Hello World!");
- , , Fn
. , call_five_times
, FnMut
, ? β ! , :
call_five_times(|| println!("Hello World!"));
, Fn
FnMut
. , : , , , . , (FnMut
) , (Fn
) .
(subtyping)? , .
?
, " ", . , , . , , . β (value/move semantics).
, (moves) . String
(Copy
able) u32
. , . , .
fn main() {
let name = String::from("Alice");
let welcome = || {
let name = name; //
println!("Welcome, {}", name);
};
welcome();
}
name
welcome
. let name = name;
. , name
? :
fn main() {
let name1 = String::from("Alice");
let welcom = || {
let mut name2 = name1;
name2 += " and Bob";
println!("Welcome, {}", name2);
};
welcome();
}
name1
. name2
, , . β , . ? name1
, welcome()
.
. call_five_times
? welcome
:
fn main() {
let name = String::from("Alice");
let welcome = || {
let mut name = name;
name += " and Bob";
println!("Welcome, {}", name);
};
call_five_times(welcome);
}
fn call_five_times<F>(f: F)
where
F: Fn(),
{
for _ in 1..6 {
f();
}
}
, FnOnce
:
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` --> main.rs:4:19 | 4 | let welcome = || { | ^^ this closure implements `FnOnce`, not `Fn` 5 | let mut name = name; | ---- closure is `FnOnce` because it moves the variable `name` out of its environment ... 10 | call_five_times(welcome); | --------------- the requirement to implement `Fn` derives from here
Fn()
FnOnce()
, ? !
error[E0382]: use of moved value: `f` --> main.rs:18:9 | 18 | f(); | ^ value moved here in previous iteration of loop | = note: move occurs because `f` has type `F`, which does not implement the `Copy` trait
f
. , f
, . , . FnOnce
.
, :
fn main() {
let name = String::from("Alice");
let welcome = || {
let mut name = name;
name += " and Bob";
println!("Welcome, {}", name);
};
call_once(welcome);
}
fn call_once<F>(f: F)
where
F: FnOnce()
{
f();
}
.
, Fn
FnMut
, , , . , Fn
FnOnce
FnOnce
, , , , .
move
, , , ( ). "Rust by Example" . , .
, . , , . , . , , . , :
fn pass_by_value(_x: String) {}
fn pass_by_ref(_x: &String) {}
fn pass_by_mut_ref(x: &mut String) {
pass_by_ref(x); //
pass_by_value(*x); //
}
fn main() {}
, . , (implicit). , . . , - , , (captured), , , .
, , , , :
- ,
- , . , (is dropped), .
- , - ( , ).
, :
, β .
, , . : , . :
fn main() {
// owned by main
let name_outer = String::from("Alice");
let say_hi || {
// force a move, again, we'll get smarter in a second
let name_inner = name_outer;
println!("Hello, {}", name_inner);
};
// main no longer owns name_outer, try this:
println!("Using name from main: {}", name_outer); // error!
// but name_inner lives on, in say_hi!
say_hi(); // success
}
, () β name_outer
, .
, . let name_inner = name_outer;
. name_outer
. , , name_outer
. ( say_hi()
). , . . , , name_outer
:
fn main() {
// owned by main
let name_outer = String::from("Alice");
let say_hi || {
// use by ref
let name_inner = &name_outer;
println!("Hello, {}", name_inner);
};
// main still owns name_outer, this is fine
println!("Using name from main: {}", name_outer); // success
// but name_inner lives on, in say_hi!
say_hi(); // success
say_hi(); // success
}
, , name_outer
say_hi
, !
fn main() {
let say_hi = { //
//
let name_outer = String::from("Alice");
// ,
|| {
// use by ref
let name_inner = &name_outer;
println!("Hello, {}", name_inner);
}
};
// , name_outer
// println!("Using name from main: {}", name_outer); // error!
say_hi();
say_hi();
}
, - : " , , , ( β .)". , . , move
:
fn main() {
let say_hi = {
let name_outer = String::from("Alice");
move || {
let name_inner = &name_outer;
println!("Hello, {}", name_inner);
}
}
say_hi();
say_hi();
}
name_outer
. - , , .
. move
, , . , :
fn main() {
let name = String::from("Alice");
let _ = move || { println!("Hello, {}", name) };
println!("Using name from main: {}", name); // error!
}
Rust
, . . , , , ? , : . Rust by Example:
, , .
let name_inner = name_outer;
. , , ( ), . .
- , .
- , , .
- , , .
, . , . , , , , .
, , move
, .
, , , move
. , , : " , " .
: ,
:
- , .
- , , , , .
- , , . , , .
- ,
move
. - :
- - ,
FnOnce
. - , - ,
FnMut
,FnOnce
. -
Fn
,FnMut
FnOnce
.
- - ,
, , , , , . Rust by example.
, :
fn call_fn<F>(f: F) where F: Fn() {
f()
}
fn call_fn_mut<F>(mut f: F) where F: FnMut() {
f()
}
fn call_fn_once<F>(f: F) where F: FnOnce() {
f()
}
main
:
fn main() {
let name = String::from("Alice");
let say_hi = || println!("Hello, {}", name);
call_fn(say_hi);
call_fn_mut(say_hi);
call_fn_once(say_hi);
}
name
, say_hi
, , , , name
. , say_hi
Fn
, FnMut
FnOnce
, .
// bad!
fn main() {
let say_hi = {
let name = String::from("Alice");
|| println!("Hello, {}", name)
};
}
, . name
. , , , . , , :
fn main() {
let say_hi = {
let name = String::from("Alice");
|| {
let name = name;
println!("Hello, {}", name)
}
};
// call_fn(say_hi);
// call_fn_mut(say_hi);
call_fn_once(say_hi);
}
FnOnce
, , . ! name
, ( - β ):
fn main() {
let say_hi = {
let name = String::from("Alice");
move || println!("Hello, {}", name)
};
call_fn(&say_hi);
call_fn_mut(&say_hi);
call_fn_once(&say_hi);
}
, Fn
, FnMut
FnOnce
. , say_hi
, call_fn
. ( ), , , . ( β .) , .
fn main() {
let say_hi = {
let name = String::from("Alice");
|| std::mem::drop(name)
};
//call_fn(say_hi);
//call_fn_mut(say_hi);
call_fn_once(say_hi);
}
drop
name
. , , , . , move
, .
fn main() {
let mut say_hi = {
let mut name = String::from("Alice");
move || {
name += " and Bob";
println!("Hello, {}", name);
}
};
//call_fn(say_hi);
call_fn_mut(&mut say_hi);
call_fn_once(&mut say_hi);
}
+=
String
, . . , name
. name
, (move
) . say_hi
, mut
.
say_hi
, &mut
, (1) , , (2) . call_fn
, FnMut
FnOnce
, Fn
.
? " and Bob"
name
?
fn main() {
let mut name = String::from("Alice");
let mut say_hi = || {
name += " and Bob";
println!("Hello, {}", name);
};
//call_fn(say_hi);
call_fn_mut(&mut say_hi);
call_fn_once(&mut say_hi);
}
name
, .
// bad!
fn main() {
let mut name = String::from("Alice");
let mut say_hi = || {
name += " and Bob";
println!("Hello, {}", name);
};
//call_fn(say_hi);
call_fn_mut(&mut say_hi);
call_fn_once(&mut say_hi);
println!("And now name is: {}", name);
}
say_hi
, println!
, name
, . - (lexical lifetimes). ( ) " " (non-lexical lifetimes), #![feature(nll)]
. , :
fn main() {
let mut name = String::from("Alice");
{
let mut say_hi = || {
name += " and Bob";
println!("Hello, {}", name);
};
//call_fn(say_hi);
call_fn_mut(&mut say_hi);
call_fn_once(&mut say_hi);
}
println!("And now name is: {}", name);
}
( , ) ( β .):
fn main() {
let mut name = String::from("Alice");
let mut say_hi = || {
println!("Hello, {}", name); // use by ref
name += " and Bob"; // use by mut ref
std::mem::drop(name); // use by value
};
//call_fn(say_hi);
//call_fn_mut(say_hi);
call_fn_oce(say_hi);
}
, , . , , , .
?
, . - . Rust Book:
,Fn
-,Fn
, , , , ,FnMut
FnOnce
.
, " , ". , β FnOnce
. , .
, Fn
. , Fn
FnMut
, FnMut
FnOnce
.
FnOnce
FnMut
Fn
, , , . , Fn
.
5
Now that we have added everything we learned about iterators and closures, change line 5 (which starts with for i in
) so that the program prints the numbers 2,4,6,...,20
twice.
fn main() {
let nums: Vec<u32> = (1..11).collect();
for _ in 1..3 {
for i in nums.map(todo!()) {
println!("{}", i);
}
}
}
:
error[E0599]: no method named `map` found for type `std::vec::Vec<u32>` in the current scope --> main.rs:5:23 | 5 | for i in nums.map(todo!()) { | ^^^ | = note: the method `map` exists but the following trait bounds were not satisfied: `&mut std::vec::Vec<u32> : std::iter::Iterator` `&mut [u32] : std::iter::Iterator`
, nums
. : into_iter()
, iter()
iter_mut()
. , , iter()
. nums.map
nums.iter().map
, todo!()
.
, . : |x| x * 2
. : FnOnce
, FnMut
Fn
?