A continuación se muestra una traducción de una parte de la serie de artículos Rust Crash Course de Michael Snoiman, que se centra en los mecanismos de paso de parámetros, iteradores y cierres con respecto a cómo se transfiere la propiedad y se relaciona con la mutabilidad y la vida útil.
También intenté traducir lo más cerca posible del estilo del autor, pero reduje algunos interdomos y exclamaciones que no son muy significativas para el significado.
Tipos de parámetros
Primero, quiero lidiar con un posible error. Este podría ser uno de esos delirios de "mi cerebro fue dañado por Haskell" que las personas imperativas no enfrentan, así que me disculpo de antemano por mis bromas sobre mí y otros haskellistas.
¿Coinciden las firmas de tipo de las dos funciones?
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
Ahora que hemos agregado todo lo que hemos aprendido sobre iteradores y cierres, cambie la línea 5 (que comienza con for i in
) para que el programa imprima los números 2,4,6,...,20
dos veces.
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
?