Найти в Дзене
Muhammed Mustafaev

Rust. Ссылочные переменные и заимствование.

Нам приходилось перемещать s в функцию и потом обратно его принимать с длиной s используя кортеж. Но теперь мы можем это более оптимизированном виде записать, используя ссылочные переменные.
fn main() {
let s = String::from("hello world");
let len = get_len(&s);
}
fn get_len(s: &String) -> usize
{
s.len() }
Мы в качестве аргумента отправляем ссылку на объект и также в параметрах указываем что это ссылка типа String. И возвращаем только длину объекта, так как s не передавала владение в функцию, она всё еще действительна.
Вспомним как хранится в памяти s. В стеке хранится ссылка на значение в куче, длинна и объем, когда мы передаем в функцию &s то передается только ссылка на объект.
Рассмотрим еще пример.
fn main() {
let s = String::from("hello");
add(&s); }
fn add(s: &String) {
s.push_str(" world"); }
в этом примере мы пытаемся в функции изменить переданное значение, но компилятор выведет ошибку. Чтобы исправить эту ошибку нам надо передать

Ссылочные переменные.
Раньше мы писали так:
fn main (){
let s = String::from("hello world");
let (s, len) = get_len(s);
}

fn get_len(s: String) -> (String, u32){
(s, s.len())
}
Нам приходилось перемещать s в функцию и потом обратно его принимать с длиной s используя кортеж. Но теперь мы можем это более оптимизированном виде записать, используя ссылочные переменные.
fn main() {
let s = String::from("hello world");
let len = get_len(&s);
}

fn get_len(s: &String) -> usize
{
s.len() }
Мы в качестве аргумента отправляем ссылку на объект и также в параметрах указываем что это ссылка типа String. И возвращаем только длину объекта, так как s не передавала владение в функцию, она всё еще действительна.
Вспомним как хранится в памяти s. В стеке хранится ссылка на значение в куче, длинна и объем, когда мы передаем в функцию &s то передается только ссылка на объект.
Рассмотрим еще пример.
fn main() {
let s = String::from("hello");
add(&s); }

fn add(s: &String) {
s.push_str(" world"); }
в этом примере мы пытаемся в функции изменить переданное значение, но компилятор выведет ошибку. Чтобы исправить эту ошибку нам надо передать изменяемую ссылку.
fn main() {
let mut s = String::from("hello");
add(&mut s); }

fn add(s: &mut String) {
s.push_str(" world"); }
Нужно при создании переменой пометить изменяемость, при передаче, и при аннотировании в функции.
Изменяемая ссылочная переменная имеет одно большое ограничение: можно иметь только одну изменяемую ссылочную переменную на часть данных в определённой области видимости. От этого ограничения предотвращает эффект гонки данных (data race) является похожим на гонки данных и возникает когда два или более указателей использует одну и туже данную. Минимум один указатель используется для записи данных. отсутствуют механизмы для синхронизации доступа к данным.
Гонка данных приводит к трудно диагностируемой ситуации и трудно исправляемой проблеме.
Если мы хотим больше одного изменяемую ссылку то это можно сделать в вложенных областях видимости. Также если мы создадим не изменяемую ссылку и потом изменяемую ссылку то также выведется ошибка при компиляции.
Область видимости ссылочной переменной начинается от места, где она создана и продолжается до места где она последний раз использована.
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} and {}", r1, r2);
let r3 = &mut s;
println!("{}", r3);
Эта программа компилируется без ошибки.