Rust by Example — страница 34 из 66

mutable_borrow.y = 2;

mutable_borrow.z = 1;

// Error! Can't borrow `point` as immutable because it's currently

// borrowed as mutable.

// let y = &point.y;

// TODO ^ Try uncommenting this line

// Error! Can't print because `println!` takes an immutable reference.

// println!("Point Z coordinate is {}", point.z);

// TODO ^ Try uncommenting this line

// Ok! Mutable references can be passed as immutable to `println!`

println!("Point has coordinates: ({}, {}, {})",

mutable_borrow.x, mutable_borrow.y, mutable_borrow.z);

// The mutable reference is no longer used for the rest of the code so it

// is possible to reborrow

let new_borrowed_point = &point;

println!("Point now has coordinates: ({}, {}, {})",

new_borrowed_point.x, new_borrowed_point.y, new_borrowed_point.z);

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

The ref pattern

When doing pattern matching or destructuring via the let binding, the ref keyword can be used to take references to the fields of a struct/tuple. The example below shows a few instances where this can be useful:

#[derive(Clone, Copy)]

struct Point { x: i32, y: i32 }

fn main() {

let c = 'Q';

// A `ref` borrow on the left side of an assignment is equivalent to

// an `&` borrow on the right side.

let ref ref_c1 = c;

let ref_c2 = &c;

println!("ref_c1 equals ref_c2: {}", *ref_c1 == *ref_c2);

let point = Point { x: 0, y: 0 };

// `ref` is also valid when destructuring a struct.

let _copy_of_x = {

// `ref_to_x` is a reference to the `x` field of `point`.

let Point { x: ref ref_to_x, y: _ } = point;

// Return a copy of the `x` field of `point`.

*ref_to_x

};

// A mutable copy of `point`

let mut mutable_point = point;

{

// `ref` can be paired with `mut` to take mutable references.

let Point { x: _, y: ref mut mut_ref_to_y } = mutable_point;

// Mutate the `y` field of `mutable_point` via a mutable reference.

*mut_ref_to_y = 1;

}

println!("point is ({}, {})", point.x, point.y);

println!("mutable_point is ({}, {})", mutable_point.x, mutable_point.y);

// A mutable tuple that includes a pointer

let mut mutable_tuple = (Box::new(5u32), 3u32);

{

// Destructure `mutable_tuple` to change the value of `last`.

let (_, ref mut last) = mutable_tuple;

*last = 2u32;

}

println!("tuple is {:?}", mutable_tuple);

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Lifetimes

A lifetime is a construct the compiler (or more specifically, its borrow checker) uses to ensure all borrows are valid. Specifically, a variable's lifetime begins when it is created and ends when it is destroyed. While lifetimes and scopes are often referred to together, they are not the same.

Take, for example, the case where we borrow a variable via &. The borrow has a lifetime that is determined by where it is declared. As a result, the borrow is valid as long as it ends before the lender is destroyed. However, the scope of the borrow is determined by where the reference is used.

In the following example and in the rest of this section, we will see how lifetimes relate to scopes, as well as how the two differ.

// Lifetimes are annotated below with lines denoting the creation

// and destruction of each variable.

// `i` has the longest lifetime because its scope entirely encloses

// both `borrow1` and `borrow2`. The duration of `borrow1` compared

// to `borrow2` is irrelevant since they are disjoint.

fn main() {

let i = 3; // Lifetime for `i` starts. ────────────────┐

//                                                     │

{ //                                                   │

let borrow1 = &i; // `borrow1` lifetime starts. ──┐│

//                                                ││

println!("borrow1: {}", borrow1); //              ││

} // `borrow1 ends. ──────────────────────────────────┘│

//                                                     │

//                                                     │

{ //                                                   │

let borrow2 = &i; // `borrow2` lifetime starts. ──┐│

//                                                ││

println!("borrow2: {}", borrow2); //              ││

} // `borrow2` ends. ─────────────────────────────────┘│

//                                                     │

}   // Lifetime ends. ─────────────────────────────────────┘

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Note that no names or types are assigned to label lifetimes. This restricts how lifetimes will be able to be used as we will see.

Explicit annotation

The borrow checker uses explicit lifetime annotations to determine how long references should be valid. In cases where lifetimes are not elided, Rust requires explicit annotations to determine what the lifetime of a reference should be. The syntax for explicitly annotating a lifetime uses an apostrophe character as follows: