Перейти до основного вмісту
Модуль 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 у функцію calculate_length за допомогою символу &.

Завантаження редактора…
Показати підказку

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

Рішення доступне після 3 спроб

вправи#rust.m3.l2.e2
Спроби: 0Завантаження…

Зробіть змінну s змінною (let 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 спроб