Перейти к содержанию

Урок №4 - Владение

Posted on:16 февраля 2023 г. at 15:20

Example Dynamic OG Image link Rust - прекрасный язык системного программирования, который, как известно, описывается как “трудный в освоении”. В этой серии мы разберем его концепции на простые для понимания части с ключевыми выводами. Надежда этой серии состоит в том, чтобы заинтересовать больше людей rust и увидеть, насколько это удивительно на самом деле. В этой статье мы продолжим серию, рассказав о владение.

Владение является центральной особенностью языка программирования Rust, и это отличает Rust от других языков программирования. Это позволяет разработчикам управлять временем жизни и объемом данных, гарантируя, что ресурсы освобождаются, когда они больше не нужны, и избегая повреждения данных и утечки ресурсов. В этой статье мы рассмотрим, что такое владение, как это работает, и несколько примеров кода, иллюстрирующих концепции.

Что такое владение в Rust?

Владение - это система, которая отслеживает жизненный цикл значений в программах Rust. В Rust значения имеют одного владельца, и когда этот владелец выходит за пределы области видимости, значение автоматически уничтожается. Это гарантирует, что ресурсы освобождаются, когда они больше не нужны, избегая повреждения данных и утечки ресурсов. Система владения предоставляет способ безопасного и эффективного управления сроком службы и объемом данных.

Принцип владения в Rust

Система владения работает путем отслеживания жизненного цикла переменной в программах Rust. Когда значение создается, ему присваивается владелец, и когда этот владелец выходит за пределы области видимости, значение уничтожается. Это делается автоматически компилятором Rust, так что вам не нужно беспокоиться о ручном освобождении ресурсов.

Одним из важных правил владения является то, что у переменной может быть только один владелец. Когда значение присваивается новому владельцу, предыдущий владелец больше не несет ответственности за это значение, и значение уничтожается, когда новый владелец выходит за пределы области видимости. Это помогает гарантировать, что ресурсы освобождаются, когда они больше не нужны.

Еще одно важное правило владения заключается в том, что значение переменной может быть только заимствовано, но не принадлежать кому-либо другому. Заимствование - это способ предоставить другой переменной временный доступ к значению, не вступая в права собственности на нее. Это полезно, например, когда вам нужно передать значение функции или использовать его в цикле. Заимствование позволяет избежать копирования значений, которое может быть медленным и дорогостоящим, и в то же время гарантировать высвобождение ресурсов, когда они больше не нужны.

Примеры кода

Вот несколько примеров кода, которые помогут проиллюстрировать концепции владения в Rust.

Пример 1: Право собственности и сроки службы

fn main() {
    let x = 5;
    let y = x;

    println!("x = {}", x);
    println!("y = {}", y);
}

В этом примере x присваивается значение 5, а затем y присваивается значение x. Поскольку значения могут иметь только одного владельца, x больше не несет ответственности за значение 5 после присвоения y. На самом деле это верно для не копируемых типов, а простые типы являются копируемыми, по этому пример не соответствует описанному ранее и x и y будут иметь, каждый свое значение в этом случае, но для более сложных не копируемых типов это было бы верно. Результатом этой программы является:

x = 5
y = 5

То что тип этих переменных является копируемым можно проверить, разграничив переменные пространством имен:

fn main() {
    let x = 5;
    {
      let y = x;
      println!("y = {}", y);
   }
    println!("x = {}", x);
}

Как видим ошибки нет, так как на самом деле x не передал владение y, а воспользовался своим методом Copy.

Пример 2: Заимствование

fn print_value(x: &i32) {
    println!("Значение: {}", x);
}

fn main() {
    let x = 5;

    print_value(&x);
    println!("Значение X равно: {}", x);
}

В этом примере функция print_value принимает ссылку на значение i32, вместо того, чтобы стать владельцем значения (фунции всегда заберут владение, если передается не ссылка, в этом случае не важно, копируемый тип или нет). Это позволяет заимствовать x, поэтому его можно использовать в функции print_value, оставаясь при этом доступным для использования в основной программе. Результатом этой программы является:

Значение: 5
Значение X равно: 5

Пример 3: Заимствование и мутабельность

fn change_value(x: &mut i32) {
  *x += 1;
}

fn main() {
  let mut x = 5;
  change_value(&mut x);
  println!("Значение X равно: {}", x);
}

В этом примере функция change_value принимает изменяемую ссылку на значение i32, вместо того, чтобы стать владельцем значения. Это позволяет изменять заимствование x, поэтому его значение может быть изменено в функции change_value. Результатом этой программы является:

Значение X равно: 6

Пример 4: Владение и замыкания

Замыкания - это анонимные функции, которые могут храниться в переменных и передаваться в качестве аргументов другим функциям. Когда замыкание определено, оно захватывает значения из среды, в которой оно было создано, либо заимствует их, либо становится владельцем.

Например:

fn main() {
    let x = 5;
    let closure = || {
        println!("Значение X равно: {}", x);
    };
    closure();
}

В этом примере замыкание фиксирует значение x, заимствуя его. Когда замыкание выполняется, оно может получить доступ к значению x, даже если x больше не находится в области видимости. Результатом этой программы является:

Значение X равно: 5

Замыкания также могут фиксировать значения, становясь их владельцами. Например:

fn main() {
    let v = vec![1, 2, 3];
    let closure = move || {
        println!("Теперь я владею вектором: {:?}", v);
    };
    closure();
    println!("Я больше не владею вектором: {:?}", v);
}

В этом примере замыкание фиксирует значение v, становясь его владельцем. Когда закрытие выполняется, оно становится владельцем вектора, и первоначальный владелец больше не может его использовать. Результатом этой программы является ошибка компиляции или предупреждение текстового редактора (если возможно).

Итог

Владение является главной особенностью языка программирования Rust, и оно предоставляет разработчикам возможность управлять временем жизни и объемом данных, гарантируя, что ресурсы освобождаются, когда они больше не нужны, и избегая повреждения данных и утечки ресурсов. Понимание концепций владения, сроков службы и заимствования имеет решающее значение для написания эффективных и безопасных программ Rust. После примеров в этой статье вы теперь сможете лучше понимать эти концепции и быть в состоянии начать использовать это в своих собственных программах Rust.