Rust на примерах — страница 18 из 65

// `first` и `second` выходят из области видимости и освобождаются

}

}

fn main() {

let rectangle = Rectangle {

// Статические методы вызываются двойными двоеточиями

p1: Point::origin(),

p2: Point::new(3.0, 4.0),

};

// Метод экземпляра вызывается с помощью оператора точка

// Обратите внимание, что первый аргумент `&self` неявно пропускается т.е.

// `rectangle.perimeter()` === `perimeter(&rectangle)`

println!("Rectangle perimeter: {}", rectangle.perimeter());

println!("Rectangle area: {}", rectangle.area());

let mut square = Rectangle {

p1: Point::origin(),

p2: Point::new(1.0, 1.0),

};

// Ошибка! `rectangle` неизменяемый, но этот метод нуждается в изменяемом

// объекте

//rectangle.translate(1.0, 0.0);

// ЗАДАНИЕ ^ Попробуйте удалить комментарий

// Хорошо, изменяемый объект может вызывать изменяемые методы

square.translate(1.0, 1.0);

let pair = Pair(Box::new(1), Box::new(2));

pair.destroy();

// Ошибка! `destroy` вызывает "съеденный" `pair`

//pair.destroy();

// ЗАДАНИЕ ^ Попробуйте удалить комментарий

}

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

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Замыкания

Замыкания в Rust, так же называемые лямбда, это функции, которые замыкают своё окружение. Для примера, замыкание, которое захватывает значение переменной x:

|val| val + x

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

Другие характеристики замыканий включают в себя:

   • использование || вместо () для аргументов.

   • опциональное ограничения тела функции ({}) для одного выражения (в противном случае обязательно).

   • возможность захвата переменных за пределами окружения

fn main() {

// Инкремент с помощью замыкания и функции.

fn  function            (i: i32) -> i32 { i + 1 }

// Замыкания анонимны. Тут мы связываем их с ссылками

// Аннотация идентичны аннотации типов функции, но является опциональной

// как и оборачивания тела в `{}`. Эти безымянные функции

// назначены соответствующе названным переменным.

let closure_annotated = |i: i32| -> i32 { i + 1 };

let closure_inferred  = |i     |          i + 1  ;

let i = 1;

// Вызов функции и замыкания.

println!("функция: {}", function(i));

println!("замыкание с указанием типа: {}", closure_annotated(i));

println!("замыкание с выводом типа: {}", closure_inferred(i));

// Замыкание не принимает аргументов, но возвращает `i32`.

// Тип возвращаемого значения выведен автоматически.

let one = || 1;

println!("замыкание, возвращающее один: {}", one());

}

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

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Захват

Замыкания довольно гибкие и делают всё, что требуется для работы с ними без дополнительных указаний. Это позволяет захватывать переменные перемещая их или заимствуя, в зависимости от необходимости. Замыкания могут захватывать переменные:

   • по ссылке: &T

   • по изменяемой ссылке: &mut T

   • по значению: T

Преимущественно, они захватывают переменные по ссылке, если явно не указан другой способ.

fn main() {

use std::mem;

let color = "green";

// Замыкание для вывода `color`, которое немедленно заимствует (`&`)

// `color` и сохраняет замыкание в переменной `print`. color` будет оставаться

// заимствованным до тех пор, пока `print` используется.

//

// `println!` принимает аргументы по неизменяемым ссылкам, поэтому он не накладывает

// дополнительных ограничений.

let print = || println!("`color`: {}", color);

// Вызываем замыкание, использующее заимствование.

print();

// `color` может быть неизменяемо заимствован, так как замыкание

// держит только неизменяемую ссылку на `color`.

let _reborrow = &color;

print();

// Перемещение или перезанятие возможно после последнего использования `print`

let _color_moved = color;

let mut count = 0;

// Замыкание для увеличения `count` может принимать как `&mut count`, так и `count`,

// но использование `&mut count` менее ограничено, так что

// замыкание выбирает первый способ, т.е. немедленно заимствует `count`.

//

// inc` должен быть `mut`, поскольку внутри него хранится `&mut`.

// Таким образом, вызов замыкания изменяет его, что недопустимо без `mut`.

let mut inc = || {

count += 1;

println!("`count`: {}", count);

};

// Вызываем замыкание, использующее изменяемое заимствование.

inc();

// Замыкание продолжает изменяемо заимствовать `count` так как оно используется дальше.

// Попытка перезанять приведёт к ошибке.

// let _reborrow = &count;

// ^ TODO: попробуйте раскомментировать эту строку.

inc();

// Замыкание больше не заимствует `&mut count`. Так что теперь

// при перезаимствовании ошибок не будет.

let _count_reborrowed = &mut count;

// Некопируемый тип.