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

println!("The person's age from person struct is {}", person.age);

}

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

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

See also:

destructuring

Borrowing

Most of the time, we'd like to access data without taking ownership over it. To accomplish this, Rust uses a borrowing mechanism. Instead of passing objects by value (T), objects can be passed by reference (&T).

The compiler statically guarantees (via its borrow checker) that references always point to valid objects. That is, while references to an object exist, the object cannot be destroyed.

// This function takes ownership of a box and destroys it

fn eat_box_i32(boxed_i32: Box) {

println!("Destroying box that contains {}", boxed_i32);

}

// This function borrows an i32

fn borrow_i32(borrowed_i32: &i32) {

println!("This int is: {}", borrowed_i32);

}

fn main() {

// Create a boxed i32, and a stacked i32

let boxed_i32 = Box::new(5_i32);

let stacked_i32 = 6_i32;

// Borrow the contents of the box. Ownership is not taken,

// so the contents can be borrowed again.

borrow_i32(&boxed_i32);

borrow_i32(&stacked_i32);

{

// Take a reference to the data contained inside the box

let _ref_to_i32: &i32 = &boxed_i32;

// Error!

// Can't destroy `boxed_i32` while the inner value is borrowed later in scope.

eat_box_i32(boxed_i32);

// FIXME ^ Comment out this line

// Attempt to borrow `_ref_to_i32` after inner value is destroyed

borrow_i32(_ref_to_i32);

// `_ref_to_i32` goes out of scope and is no longer borrowed.

}

// `boxed_i32` can now give up ownership to `eat_box` and be destroyed

eat_box_i32(boxed_i32);

}

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

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Mutability

Mutable data can be mutably borrowed using &mut T. This is called a mutable reference and gives read/write access to the borrower. In contrast, &T borrows the data via an immutable reference, and the borrower can read the data but not modify it:

#[allow(dead_code)]

#[derive(Clone, Copy)]

struct Book {

// `&'static str` is a reference to a string allocated in read only memory

author: &'static str,

title: &'static str,

year: u32,

}

// This function takes a reference to a book

fn borrow_book(book: &Book) {

println!("I immutably borrowed {} - {} edition", book.title, book.year);

}

// This function takes a reference to a mutable book and changes `year` to 2014

fn new_edition(book: &mut Book) {

book.year = 2014;

println!("I mutably borrowed {} - {} edition", book.title, book.year);

}

fn main() {

// Create an immutable Book named `immutabook`

let immutabook = Book {

// string literals have type `&'static str`

author: "Douglas Hofstadter",

title: "Gödel, Escher, Bach",

year: 1979,

};

// Create a mutable copy of `immutabook` and call it `mutabook`

let mut mutabook = immutabook;

// Immutably borrow an immutable object

borrow_book(&immutabook);

// Immutably borrow a mutable object

borrow_book(&mutabook);

// Borrow a mutable object as mutable

new_edition(&mut mutabook);

// Error! Cannot borrow an immutable object as mutable

new_edition(&mut immutabook);

// FIXME ^ Comment out this line

}

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

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

See also:

static

Aliasing

Data can be immutably borrowed any number of times, but while immutably borrowed, the original data can't be mutably borrowed. On the other hand, only one mutable borrow is allowed at a time. The original data can be borrowed again only after the mutable reference has been used for the last time.

struct Point { x: i32, y: i32, z: i32 }

fn main() {

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

let borrowed_point = &point;

let another_borrow = &point;

// Data can be accessed via the references and the original owner

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

borrowed_point.x, another_borrow.y, point.z);

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

// borrowed as immutable.

// let mutable_borrow = &mut point;

// TODO ^ Try uncommenting this line

// The borrowed values are used again here

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

borrowed_point.x, another_borrow.y, point.z);

// The immutable references are no longer used for the rest of the code so

// it is possible to reborrow with a mutable reference.

let mutable_borrow = &mut point;

// Change data via mutable reference

mutable_borrow.x = 5;