Перейти к содержанию

Компоновка памяти

Posted on:7 февраля 2023 г. at 13:04

Example Dynamic OG Image link Байтовые представления общих типов.

Базовые типы

Основные типы встроены в ядро языка.

Безнаковые типы

ТипМаксимальное значение
u8255
u1665_535
u324_294_967_295
u6418_446_744_073_709_551_615
u128340_282_366_920_938_463_463_374_607_431_768_211_455
usizeВ зависимости от размера указателя платформы, аналогично u16, u32 или u64.

Типы со знаком

ТипМаксимальное значение
i8127
i1632_767
i322_147_483_647
i649_223_372_036_854_775_807
i128170_141_183_460_469_231_731_687_303_715_884_105_727
isizeВ зависимости от размера указателя платформы, аналогично i16, i32 или i64.
ТипМинимальное значение
i8-128
i16-32_768
i32-2_147_483_648
i64-9_223_372_036_854_775_808
i128-170_141_183_460_469_231_731_687_303_715_884_105_728
isizeВ зависимости от размера указателя платформы, аналогично i16, i32 или i64.

Типы с плавающей точкой

Представление битовой выборки для f32: Разъяснение:

f32S (1)E (8)F (23)Значение
Нормализованное число±1 до 254любое$±(1.F)_{2} * 2$$^E$$^-$$^1$$^2$$^7$
Денормализованное число±0ненулевой$±(0.F){_2} * 2$$^-$$^1$$^2$$^6$
Нуль±00$±0$
Бесконечность±2550$±∞$
Некорректное±255ненулевойNaN

Аналогично, для типов f64 это будет выглядеть как:

f64S (1)E (11)F (52)Значение
Нормализованное число±1 до 2046любое$±(1.F)_{2}$ * 2$^E$$^-$$^1$$^0$$^2$$^3$
Денормализованное число±0ненулевой$±(0.F){_2} * 2$$^-$$^1$$^0$$^2$$^2$
Нуль±00$±0$
Бесконечность±20470$±∞$
Некорректное±2047ненулевойNaN

Преобразование типа через as

ПреобразованиеРезультатКомментарий
3.9_f32 as u83Усечение, сначала рассмотрите x.round().
314_f32 as u8255Получает ближайшее доступное число.
f32::INFINITY as u8255То же самое относится к БЕСКОНЕЧНОСТИ как к действительно большому числу.
f32::NAN as u80-
_314 as u858Усечение избыточных битов.
_200 as i856-
_257 as i8-1-

Арифметические подводные камни

ПреобразованиеРезультатКомментарий
200_u8 / 0_u8Ошибка компилятора-
200_u8 / _0ПаникаРегулярная математика может паниковать, деление на ноль.
200_u8 + 200_u8Ошибка компилятора-
200_u8 + _200ПаникаВ режиме отладки используйте проверку, вместо _.
200_u8 + _200144В режиме компиляции это приведет к переполнению.
1_u8 / 2_u80Другие целочисленные деления усекаются.
0.8_f32 + 0.1_f320.90000004-
1.0_f32 / 0.0_f32f32::INFINITY-
0.0_f32 / 0.0_f32f32::NAN-
x < f32::NANfalseNAN всегда возвращают значение false.
x > f32::NANfalse-
f32::NAN == f32::NANfalse-

Выражение _100 означает все, что может содержать значение 100, например, 100_i32, но является непрозрачным для компилятора.

Текстовые типы

Базовые:

ТипКомментарий
charВсегда 4 байта и содержит только одно значение Юникода.
strМассив u8 неизвестной длины, содержащий символы в кодировке UTF-8.

Применение:

СимволыКомментарий
let c = ‘a’;Симвод юникода.
let c = ’❤‘;Может содержать любые символы Юникода.
let c = ‘❤️’;Но не всегда. Данный эмодзи представляет собой два символа (см. Кодирование) и не может быть в ‘c’.
c = 0xffff_ffff;Кроме того, символы не могут содержать произвольные битовые комбинации.
СтрокиКомментарий
let s = “a”;Обычно str никогда не используется непосредственно, используется как &str.
let s = “❤❤️”;Может содержать произвольный текст, имеет переменную длину в ‘с’, трудно индексировать.

Кодирование let t = “I ❤️ Rust”; let t = “I ❤️ Rust”;

ВариантПредставление в памятиПримечание
s.as_bytes()49 20 e2 9d a4 20 52 75 73 74Обратите внимание, как ❤️, имея кодировку Юникода (U+2764), представляется как 64 27 00 00 внутри символа, и получил кодировку UTF-8 до e2 9d a4 в str.
s.chars()49 00 00 00 20 00 00 00 64 27 00 00 20 00 00 00 52 00 00 00 75 00 00 00 73 00 …Результат собирается в массив и передается в байты.
t.as_bytes()49 20 e2 9d a4 ef b8 8f 20 52 75 73 74Также наблюдайте, как эмодзи красное ❤️, представляет собой комбинацию ❤️ и селектора вариантов U+FE0F, таким образом, ‘t’ имеет более высокое количество символов, чем ‘s’.
t.chars()49 00 00 00 20 00 00 00 64 27 00 00 0f fe 01 00 20 00 00 00 52 00 00 00 75 00 …Результат собирается в массив и передается в байты.

Пользовательские типы

Основные типы, определяемые пользователем. Актуальное представление объекта. Следует также отметить, что два типа A(X, Y) и B(X, Y) с точно такими же полями, могут иметь различную структуру; transmute() не гарантирует расположение.

Ссылки и указатели

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

Должна быть задана допустимая величина ‘T’, и любая такая переменная должна существовать по крайней мере ‘а.

Метаданные указателя

Многие типы ссылок и указателей могут содержать дополнительное поле, метаданные указателей. Это может быть длина элемента или информация о объекте или указатель на таблицу vtable. Указатели с метаданными называются жирными, иначе тонкими.

Нет метаданных. (указатель тонкий).

Если T является структурой, такой как S {x: [u8]} метаданные поля len является числом. размер контента.

Регулярная ссылка среза (т.е. ссылочный тип среза [T]) часто рассматривается как &[T].

Ссылка на строковый фрагмент (т. е. ссылочный тип строкового типа str), причем метаданные len является длиной среза.

Метаданные указывают на таблицу vtable, где Drop::drop(), Trait::f(), … являются указателями на их соответствующий impl для Т.

Замыкания

Функции с автоматически управляемым захватом блоков данных. Например, если у вас:

let y = ...;
let z = ...;

with_closure(move |x| x + y.f() + z); // y и z перемещаются в функцию замыкания (типа C1)
with_closure(     |x| x + y.f() + z); // y и z используются в функции замыкания (типа C2)

Немного упрощенная функция, это замыкание, является удобной для записи «мини-функцией», которая принимает параметры, но также имеет некоторые локальные переменные для выполнения своей работы. Этот тип (содержит нужные локальные переменные) в функции. «Захват переменных» - это модный способ сказать, что замыкание удерживает локальные переменные, либо по перемещенному значению, либо по указателю.

Генерируемые анонимные замыкания типов C1 и C2, переданные в with_closure(), будут выглядеть следующим образом: Также создает анонимные функции, такие как f$_c$$_1$ (C1, X) или f$_c$$_2$ (& C2, X). Подробности зависят от того, какие FnOnce, FnMut, Fn… поддерживается на основе свойств используемых типов.

Типы переменных стандартной библиотеки

Стандартная библиотека rust объединяет вышеперечисленные примитивные типы c другими типами с особой семантикой, например:

Волшебный тип, допускающий совмещенную мутабельность.

Позволяет T’s перемещаться внутрь и наружу.

Также поддерживают динамическое заимствование T. Cell работает с Send, но не с Sync.

Запрещает T::drop() быть вызванным.

Этот тип аналогично.

Тег может быть опущен для определенных T, например NonNull.

Либо некоторая ошибка E, либо значение T.

Неинициализированная память или некоторые Т. Это легальный способ работы с неинициализированными данными.

Хранение коллекций

Для некоторых T стек-прокси может нести метаданные (например, Box<[T]>).

Вектор массива значений одного типа.

Элементы head и tail имеют значение null или указывают на узлы на куче. Каждый узел может указывать на свой предыдущий и следующий узел.

Заголовок индекса выбирает массив в качестве кольцевого буфера. Это означает, что содержимое может быть несмежным и пустым посередине, как показано выше.

Другие коллекции

Сохраняет ключи и значения в куче в соответствии с хеш-значением. HashSet идентичен HashMap, просто типа V нет. Представление кучи значительно упрощено.

В куче сохранен массив с 2N элементами на слой. Каждый Т может иметь 2 нижестоящих элемента в слое ниже. Каждый Т выше своего ребенка.

Другие строки

Обратите внимание, чем строка отличается от &str и &[char].

NUL-окончание, но без NUL в середине.

Инкапсулирует, как работает операционная система представляя строки (например, WTF-8 в Windows).

Инкапсулирует, как работает операционная система представляя пути.

Совместное владение

Если тип не содержит Cell for T, то это часто комбинируется с одним из типов Cell (тип для примера), чтобы обеспечить общую фактическую мутабельность.

Совместное владение T в одном потоке. Для разрешения мутации требуется вложенное значение или ссылка на него. Это не передача и не синхронизация.

То же самое, но разрешить совместное использование между потоками, если они содержат T, это передача или синхронизация.

Внутренние поля зависят от платформы. Должны удерживается в Arc для разделения между разъединенными потоками, или через scope() для потоков с областью действия.