Приложения - Словарь терминов Rust

Содержание: Ownership (Владение) Borrowing (Заимствование) Lifetime (Время жизни) Trait (Трейт) Crate (Крейт) Pattern Matching (Сопоставление с образцом) Unsafe (Небезопасный код)

Словарь терминов

1. Ownership (Владение)

Определение: Владение — это ключевая концепция Rust, которая управляет тем, как память выделяется и освобождается. Каждое значение в Rust имеет "владельца" (owner), и когда владелец выходит из области видимости, память автоматически освобождается.

fn main() {
    let s = String::from("hello"); // s становится владельцем строки
    // Здесь s владеет памятью
} // s выходит из области видимости, память освобождается
    

Нюансы: Владение предотвращает ошибки вроде двойного освобождения памяти или использования указателей после освобождения. Передача владения (move) происходит при присваивании или передаче в функцию, если тип не реализует трейт Copy.

Примечание: Типы вроде i32 или bool реализуют Copy, поэтому они копируются, а не перемещаются.

2. Borrowing (Заимствование)

Определение: Заимствование позволяет временно использовать значение без передачи владения. В Rust есть два типа заимствования: изменяемое (&mut) и неизменяемое (&).

fn main() {
    let mut s = String::from("hello");
    let r1 = &s; // Неизменяемое заимствование
    let r2 = &mut s; // Изменяемое заимствование
    r2.push_str(", world");
    println!("{}", r1); // Ошибка: r1 не может использоваться после &mut
}
    

Нюансы: В Rust действует правило: либо одно изменяемое заимствование, либо любое количество неизменяемых, но не оба одновременно. Это предотвращает гонки данных (data races).

Предупреждение: Нарушение правил заимствования приведёт к ошибке компиляции. Всегда проверяйте области видимости ссылок.

3. Lifetime (Время жизни)

Определение: Время жизни — это аннотация ('a), указывающая, как долго ссылка остаётся действительной. Оно необходимо для обеспечения безопасности ссылок в функциях и структурах.

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

fn main() {
    let s1 = String::from("long");
    let s2 = String::from("short");
    let result = longest(&s1, &s2);
    println!("Longest: {}", result);
}
    

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

4. Trait (Трейт)

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

trait Printable {
    fn print(&self) {
        println!("Default print");
    }
}

struct Item {
    name: String,
}

impl Printable for Item {
    fn print(&self) {
        println!("Item: {}", self.name);
    }
}

fn main() {
    let item = Item { name: String::from("Book") };
    item.print(); // Выведет: Item: Book
}
    

Нюансы: Трейты используются для обобщённого программирования (generics) и динамической диспетчеризации через dyn Trait.

5. Crate (Крейт)

Определение: Крейт — это единица компиляции в Rust, которая может быть библиотекой или исполняемым файлом. Корневой файл крейта — это обычно main.rs (для бинарного крейта) или lib.rs (для библиотеки).

// main.rs
mod my_module {
    pub fn hello() {
        println!("Hello from module!");
    }
}

fn main() {
    my_module::hello();
}
    

Нюансы: Крейты управляются через Cargo, инструмент сборки Rust. Внешние крейты подключаются через Cargo.toml.

6. Pattern Matching (Сопоставление с образцом)

Определение: Сопоставление с образцом — это мощный механизм для работы с данными через конструкции вроде match и if let.

fn main() {
    let number = Some(7);
    match number {
        Some(n) if n > 0 => println!("Positive: {}", n),
        Some(n) => println!("Non-positive: {}", n),
        None => println!("None"),
    }
}

Нюансы: match требует исчерпывающего покрытия всех вариантов, что делает код надёжным.

7. Unsafe (Небезопасный код)

Определение: Блок unsafe позволяет обойти некоторые проверки безопасности Rust, например, для работы с сырыми указателями или вызова C-кода.

fn main() {
    let mut num = 5;
    let ptr = &mut num as *mut i32;
    unsafe {
        *ptr = 10; // Изменение через сырой указатель
    }
    println!("{}", num); // Выведет: 10
}

Нюансы: Использование unsafe требует осторожности, так как оно может привести к неопределённому поведению (UB).

Предупреждение: Используйте unsafe только там, где это действительно необходимо, и документируйте свои действия.