Привет.
Статья не предполагает, что вы узнаете что-то новое из Rust, или вы научитесь ему. Это скорее эксперимент показать ребенку как он выглядит изнутри (Rust, не ребенок), а не как на нем надо писать.
То есть, еще раз, разработчики привыкли смотреть на язык с позиции как надо им, и если язык не укладывается в их парадигму, это начинает бесить.
Тут я постарался посмотреть на ситуацию с точки зрения "книжки с картинками", как язык живет, а не как мы привыкли.
Дисклеймер — в статье речь не про Copy-тип, к которым относятся, например,
i32
,f64
,bool
,char
,&T
. А про move-типы (например, String), которые перемещают значения.
Ну, попробуем.
Отталкиваемся от того, что в Rust значением (ячейкой памяти) может владеть только одна переменная. Введем обозначения: let
— "позволим", =
— "владеть", и еще mut
— кеш, наличка (деньги).
let
Позволим a
владеть House:
let a = String::from("House");
Позволим b
владеть этим House. По всем правилам, предыдущий владелец уходит из дома.
let b = a;
Теперь:
println!("a = {}", a);
Будет ошибочка, a
теперь не имеет прав что-либо делать со значением (своим House), так он его отдал.
mut
Но и это еще не все, владеть это лишь как арендовать чужой House. Вы не можете его изменять.
Тут снова будет ошибка:
b.push_str(" with Pool");
Если вы хотите его менять, вы должны купить House, за валюту mut
:
let mut c = b;
c.push_str(" with pool");
println!("{}", c);//House with pool
&
Мы можем разделить владение House, например, пустив жить приятеля. Ты передаешь приятелю связку ключей (&
):
let d = &c;
println!("{}", c);
println!("{}", d);
Но есть нюанс. По правилам приличия, если пустили гостей, нельзя делать ремонт. Следующий код даст ошибку:
let d = &c;
c.push_str(" with sandbox");// если пустили гостей, нельзя делать ремонт
println!("{}", c);
println!("{}", d);// вот гость
Можно дождаться пока гости уйдут:
let d = &c;
println!("{}", d);// тут гость вышел
c.push_str(" with sandbox");
Непонятно? В самом конце статьи есть пояснение про гостей.
& mut
Но тут приятель захотел еще джакузи. Так как это вносит изменение в House, ты просишь оплатить часть House и тогда он может менять твой House тоже. Ты передаешь ему ключи в обмен на деньги (&mut
).
let e = &mut c;
e.push_str(" and with hot tub");
println!("{}", e);
Не забывайте, что правило действует то же — при гостях ты уже не можешь делать ремонт. Более того! Пока твой приятель сидит в джакузи, ты не можешь даже зайти в дом:
let e = &mut c;
e.push_str(" and with hot tub");
println!("{}", c);
println!("{}", e);// приятель в джакузи
Надо дождаться, пока он выйдет:
let e = &mut c;
e.push_str(" and with hot tub");
println!("{}", e);// приятель вышел
println!("{}", c);
Это именно когда мы дали аренду за деньги &mut
, а не пустили пожить бесплатно (&
).
mut &mut
Сдаем в аренду другому приятелю House с правом изменения. Но приятель обладает еще своим кешем (деньгами) mut
:
let mut f = &mut c;
f.push_str(" and with garden");
Дела идут в гору, мы покупаем Apartment:
let mut c2 = String::from("Apartment");
Приятель не отстает — дай, говорит, еще и Apartment погонять, кеш у меня есть (let mut f
). Он съезжает с House, заезжает в Apartment, меняет и ее:
f = &mut c2;
f.push_str(" with elevator");
Принцип тот же — ключи на деньги — &mut
. А инициализация let mut f
нам позволяет не привязываться к одному месту (менять его). Другими словами, это про разное.
Когда приятель ушел, мы имеем по факту и измененный House и Apartment:
println!("c: {}", c);
println!("c2: {}", c2);
//c: House with pool and with sandbox and with hot tub and with garden
//c2: Apartment with elevator
Заметьте, под "приятель ушел" я имею в виду буквально "ушел", его нет, все. Rust следит за этим, и, если далее по коду переменная не применяется, он разрешает продолжить работу с вашей собственностью. Поэтому в примерах выше было ломающее мозг поведение — пока гость дома, нельзя что-то делать, но нет явных признаков, что он ушел. Переменная не применяется далее по коду — Rust считает ее "ушедшей", как-будто применили к ней delete
.
Функции
За редкими исключениями, принцип тот же, не буду здесь ими грузить. Может быть в другой раз :)
Комментарии (9)
pnmv
12.06.2025 04:55мне кажется, попытка экстраполяции "повседневного опыта", в данном случае, выглядит как непреднамеренное переусложнение и запутывание.
с другой стороны, хочется, чтобы пришел дворник и подмёл за очередным съехавшим другом или владельцем, передавшим права на дом другому лицу. может показаться, что это добавило бы статье ненужной воды, но, на самом деле, в данном случае, это не вода, а клей (или цемент), не позволяющий развалиться сюжету.
(mut - больше похоже не на валюту, а на доверенность)
anton_dolganin Автор
12.06.2025 04:55Да, Rust по сути и добавляет там дворника. Может быть это действительно улучшило бы понимание, спасибо ;)
(сначала прочитал "съехавший" в контексте "сумасшедший" :D)
SemenMartynov
12.06.2025 04:55Понравилась аналогия с ключами (&), даже визуально в этом что-то есть.
Но вот с деньгами -- как то не очень...let mut c = b;
Тут возникает странный момент:
b
не мог сам ничего изменить в доме, но смог его продать... Да ещё и с бОльшими правами, чем обладал сам. А ещё по итогу сделки деньги исчезают вместе сb
...anton_dolganin Автор
12.06.2025 04:55Согласен, притянуто :) , но в свое время я намучился с пониманием этой магии. Тут снова к Расту вернулся, решил освежить в памяти, и понял, что спотыкаюсь. Решил разложить по полочкам для себя. А потом подумал, что может кому еще полезно будет.
Но в первой части статьи можно провести аналогии с общагой и студентами. Помню, маленькие комнаты на одного были на вес золота. Просто это вообще запутало бы :DSemenMartynov
12.06.2025 04:55Помню, маленькие комнаты на одного были на вес золота.
Просто они на стеке были))) А более крупные Box-ы нужно в куче выделять...
PraetorPavel
12.06.2025 04:55Мне кажется, что объяснения в таком духе (аналогии) типа &mut &[T] могут оказаться сложнее чем сама суть ;)
panter_dsd
Интересный подход к объяснению. Жду статьи, где будет так же рассказано про поведение гостей и хозяев в move/async мире :)
anton_dolganin Автор
Спасибо за проявленный интерес!