Перейти к основному содержимому
Модуль 3 · Урок 2 из 26/14 в курсе~15 min
Уроки модуля (2/2)

Ссылки и заимствование

В Rust передача права собственности туда и обратно может быть утомительной. Чтобы решить эту проблему, Rust использует ссылки (&).

Создание ссылки на значение называется Заимствованием.

Неизменяемые ссылки

Ссылка объявляется путем добавления к типу или переменной префикса символа &. По умолчанию ссылки неизменяемы: они позволяют читать значение, но не изменять его.

Rust
fn main() {
    let s1 = String::from("hello");

    // We pass a reference to s1, not ownership
    let len = calculate_length(&s1);

    // s1 is still usable here!
    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize { // s is a reference to a String
    s.len()
} // Here, s goes out of scope, but since it doesn't own the value, nothing happens

Изменяемые ссылки

Если вам нужно изменить заимствованное значение, вы должны использовать изменяемую ссылку с &mut. Исходную переменную также необходимо объявить изменяемой с помощью mut:

Rust
fn main() {
    let mut s = String::from("hello");

    // We pass a mutable reference
    change(&mut s);

    println!("{}", s); // Prints "hello, world"
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

Правила заимствования

Чтобы предотвратить повреждение памяти и гонки данных во время компиляции, Rust применяет два фундаментальных правила:

  1. Вы можете одновременно иметь любое количество неизменяемых ссылок (&T) на значение.
  2. ИЛИ вы можете иметь только одну изменяемую ссылку (&mut T) на значение одновременно.

Вы абсолютно не можете смешивать неизменяемые и изменяемые ссылки для одного и того же значения в одной области:

Rust
let mut s = String::from("hello");

let r1 = &s; // Valid
let r2 = &s; // Valid
// let r3 = &mut s; // COMPILATION ERROR! You cannot create &mut s if s is already borrowed as immutable

Объем ссылки и нелексическое время жизни (NLL)

Исторически область действия ссылки сохранялась до конца блока, в котором она была создана. Сегодня компилятор Rust стал умнее благодаря Нелексическому времени жизни (NLL): область действия ссылки заканчивается в последней фактически используемой строке, а не обязательно в конце блока.

Это делает следующий код совершенно корректным:

Rust
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} and {}", r1, r2); // Last use of r1 and r2. The immutable references expire here!

let r3 = &mut s; // Valid! No active immutable references exist at this point

Попробуйте сами

Упражнение#rust.m3.l2.e1
Попыток: 0Загрузка…

Передайте неизменяемую ссылку s1 в функцию Calculation_length, используя символ &.

Загрузка редактора…
Показать подсказку

Замените `/* TODO \_/`на`&s1`, чтобы передать неизменяемую ссылку на строку.

Решение доступно после 3 попыток

Упражнение#rust.m3.l2.e2
Попыток: 0Загрузка…

Сделайте переменную s изменяемой (пусть mut s) и передайте изменяемую ссылку (&mut s) в функцию изменения, чтобы она могла изменить строку.

Загрузка редактора…
Показать подсказку

Используйте `let mut s`вместо`let s` и вызовите`change(&mut s);`.

Решение доступно после 3 попыток

Упражнение#rust.m3.l2.e3
Попыток: 0Загрузка…

Declare a variable s containing String::from("Rust"). Create two distinct immutable references r1 and r2 to s, and finally print both references separated by a space using the println! macro.

Загрузка редактора…
Показать подсказку

Assign `let r1 = &s;` and `let r2 = &s;` to obtain two immutable references, then print them with `println!("{} {}", r1, r2);`.

Решение доступно после 3 попыток