Как мы помним, в си++ ссылки появились как инструмент упрощающий работу с указателями. По сути это синтаксический сахар и внутри мы имеем указатели, а значит ссылки явно или не явно имеют значение типа в своем определении. Ссылки очень полезны в работе, т. к. мы не копируем сами области памяти с данными, а копируем только значения адресов памяти, что значительно меньше нагружает систему и ускоряет работу приложения. Например, при передаче больших данных в функцию и из нее, мы можем избежать дублирования этих данных. В отличие от ссылок в C++, где ссылки по умолчанию позволяют модифицировать данные, в Rust по умолчанию эти данные не доступны для модификации. Чтобы сделать возможным изменение данных потребуется использовать mut в определении ссылки. Например, let r_xx = &mut xx;. Чтобы изменить значение, на которое указывает ссылка, нам нужно разыменовать ссылку с помощью оператора *, например: *r_xx = 10;.
Обращаю ваше внимание на то, что обозначение ссылки (включая возможность модификации) производится явно и для параметра, и для аргумента функции. Это отличает Rust от C++ в лучшую сторону, т.к. при передаче аргумента в си++ (без указания, что мы передаем по ссылке), затрудняется чтение и понимание кода и требуется знания параметров функции, благо современные IDE облегчают эту задачу. По умолчанию ссылка может быть проинициализирована один раз и мы не можем ее изменить до тех пор, пока не укажем еще один mut в определении: let mut r_xx = &mut xx;. Теперь мы можем присвоить ей новое значение, например: r_xx = &mut yy;. Но есть еще одно отличие от C++ в котором, мы можем иметь несколько модифицирующих ссылок на один объект, что в свою очередь снижает безопасность. В Rust это невозможно, в определенной области для одного ресурса мы можем иметь только одну модифицирующую ссылку ИЛИ несколько не модифицирующих. Это ограничение предотвращает гонку за данными. При необходимости мы можем разделить ссылки в разных областях действия или блоках.
При передаче по ссылке не происходит передачи владения ресурсом, при окончании времени жизни ссылки не происходит уничтожения значения и освобождения памяти. Область действия ссылки начинается с того места где она была введена и продолжается до того места где она была последний раз использована. Если области действия ссылок не пересекаются, то гонки за данными не происходит. При возврате ссылки на локальную переменную из функции, в отличие от C++ в Rust потребуется указать специальный атрибут времени жизни, что предотвратит создание опасных висячих ссылок, об этом мы поговорим следующий раз. Вместо этого можно вернуть саму локальную переменную, при этом по умолчанию, для пользовательских типов, произойдет перемещение владения без дублирования ресурса.
#![allow(unused_assignments)]
fn main() {
//&i32 - reference to i32
let xx = 0;
let r1_xx = &xx;
println!("{}", r1_xx);
//&mut i32 - reference to mutable i32
let mut yy = 1;
let r2_yy = &mut yy;
//* - dereference
*r2_yy = 2;
println!("{}", r2_yy);
//&i32 - mutable reference to i32
let zz = 3;
let mut r3_zz = &xx;
r3_zz = &zz;
println!("{}", r3_zz);
let mut v = vec![1, 2, 3];
//mutable reference as function argument
foo(&mut v);
println!("{:?}", v);
let vec = vec![1, 2, 3, 4, 5];
//reference to element
for elem in vec.iter() { //elem: &i32 - reference
print!("{} ", *elem); //* - explicit dereference
}
}
//mutable reference as function parameter
fn foo(v: &mut Vec<i32>) {
// i: &mut i32
for i in v {
//*i - dereference
*i += 1;
}
}
Перегуд В.
Комментариев нет:
Отправить комментарий