TGViewer
DEV: Рубиновые тона DEV: Рубиновые тона @dev_in_ruby_colors · 3.28K subscribers
Post #1015 1.3K
К вопросу об указателях, в том числе и умных, в Rust

Система владения и заимствования в Rust, а также наличие разнообразных указателей может сильно запутать поначалу, особенно когда выясняется, что указатели бывают умные, а бывают - не очень. Это не говоря о том, что у нас есть referencing, а есть ещё dereferencing, и всё это вместо нужно как-то увязать. Попробуем разобраться.

Есть вот такой код:

let a = 5;
let b = &a;


a будет иметь тип i32, эта переменная "знает", где лежит число 5. Так как это простой тип данных, то число лежит в стеке. Кроме того, помним, что a "владеет" этим числом и в нужный момент должна удалить соответствующие данные.

В случае с b мы используем оператор referencing &, то есть фактически делаем указатель. Тип b будет &i32, эта переменная знает, у кого спросить, где находится нужное число (знает это а). При этом b не получает владение этим числом. Больше того, мы не можем даже сравнить а и b напрямую, код a == b; вернёт ошибку - типы разные, мы не можем сравнить само число i32 и указатель на него.

Однако никто не мешает нам сказать "дай мне то значение, которое лежит по этому указателю". Для этого используется оператор dereferencing, "звёздочка":

a == *b;


Теперь сравнение работает. Причём мы можем даже присвоить это значение другой переменной:

let mut c = *b;
c = c + 1;


Но значит ли это, что изменение c приведёт к измению a и/или b? На самом деле, нет. Мы опять же работаем с простым типом данных, и присваивание приводит к тому, что значение копируется для другой переменной, то есть a и c имеют разные, независимые значения.

С типами вроде vec и string ситуация похожая, но становится несколько сложнее.

let a = vec![1, 2, 3];


Мы создали вектор из трёх элементов, и мы знаем, что он будет хранится в heap, потому что потенциально его длина может меняться. В стек Rust может поместить только значения, размер которых точно известен во время компиляции, и вектор к такому типу (в отличие от фиксированного массива) не относится.

Но тогда вопрос: что же содержит в себе переменная a? Она по крайней мере должна знать, с какого адреса в heap начинается наш вектор и какой у него размер. То есть выходит, что это тоже какой-то указатель. Но "простой" указатель в духе &b данными не владеет, а просто ссылается на них. В нашем же случае мы явно ожидаем, что a владеет вектором, ведь кто-то же должен в итоге очистить память.

Ответ заключается в том, что vector (как и string) - это умный указатель, smart pointer, который действительно указывает на heap, но при этом владеет данными там и имеет пристыкованные метаданные.

Значит, если мы напишем

let b = &a;


то мы фактически тоже создадим указатель, который в свою очередь будет ссылатьcя на "умный указатель", и это, как говорится, две большие разницы.

К подобным типам данных тоже можно попытаться применить dereferencing, но вот такая строка выдаст ошибку:

let c = *b;


В отличие от простых типов данных, вектора и строки при присваивании не копируются, а переносятся. То есть к примеру вот такое

let a = vec![1, 2, 3];
let d = a;


приведёт к тому, что вектор "перенесётся" в d, ну то есть на него теперь указывает другая переменная. Когда же мы делаем let c = *b;, то мы фактически пытаемся через b влезть в данные a и сделать перемещение. Компилятору такой манёвр не сильно нравится, а скопировать весь вектор автоматом тоже не выходит, такую команду мы должны отдать сами:

let c = (*b).clone();


Это сработает, но мы именно полностью копируем вектор, он будет независим от вектора a.

Но тут можно задать новый вопрос - раз a тоже является указателем, можем мы сможем сделать dereferencing для него? Можно попробовать:

let b = *a;


Тип b определится как [i32], но программа не скомпилируется. Фактически мы пытается влезть напрямую в данные, на которые указывает умный указатель, и это получается просто массив. Массивы в Rust фиксированные и лежат в стеке, но Rust не может сунуть этот конкретный массив в стек, потому что неизвестна его длина в текущий момент времени!

Если вы думаете, что это всё, то ничуть не бывало. Есть ещё метод, который называется .deref():
  • 👍 6
More from @dev_in_ruby_colors
  1. Sep 28, 2026Github буйствует
  2. Sep 26, 2026В этом уроке по абстрактной алгебре говорим про области целостности, делители нуля, характ…
  3. Sep 22, 2026А тем временем сказ о ведьмаке, потерявшем память, уже доступен в виде аудиокниги. Целых 1…
  4. Sep 20, 2026В этом уроке по абстрактной алгебре продолжаем говорить о кольцах: в частности о subrings…
  5. Sep 17, 2026Сделал обзор актуальных библиотек JS для сбора данных, 10 штук бодрых решений на все случа…
  6. Sep 13, 2026В общем, мне тут особо было нечего делать и я подумал создать небольшой скрипт для решения…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →