Термін "покажчик жиру" використовується для позначення посилань та необроблених покажчиків на типи динамічного розміру (DST) - фрагменти або об'єкти ознак. Покажчик жиру містить покажчик плюс деяку інформацію, яка робить літній час "повним" (наприклад, довжина).
Найчастіше використовувані типи в Rust не є літнім часом, але мають фіксований розмір, відомий під час компіляції. Ці типи реалізації на Sizedмежу . Навіть типи, які керують буфером купи динамічного розміру (наприклад Vec<T>), такі Sizedяк компілятор знає точну кількість байт, яку Vec<T>екземпляр займе у стеку. В даний час в Русті існує чотири різні типи літнього часу.
Фрагменти ( [T]і str)
Тип [T](для будь-якого T) має динамічний розмір (так само, як і спеціальний тип "зріз рядка" str). Ось чому ви зазвичай бачите це лише як &[T]або &mut [T], тобто за посиланням. Це посилання є так званим "жировим покажчиком". Давайте перевіримо:
dbg!(size_of::<&u32>());
dbg!(size_of::<&[u32; 2]>());
dbg!(size_of::<&[u32]>());
Це друкує (з деяким очищенням):
size_of::<&u32>() = 8
size_of::<&[u32; 2]>() = 8
size_of::<&[u32]>() = 16
Отже, ми бачимо, що посилання на звичайний тип, наприклад, u32має 8 байт, як і посилання на масив [u32; 2]. Ці два типи не є літнім часом. Але як [u32]і на літній час, посилання на нього вдвічі більше. У випадку зрізів додатковими даними, які "завершують" літній час, є просто довжина. Тож можна сказати, що представлення &[u32]приблизно такого:
struct SliceRef {
ptr: *const u32,
len: usize,
}
Об'єкти ознак ( dyn Trait)
При використанні ознак як об'єктів ознак (тобто тип стирається, динамічно відправляється), ці об'єкти ознак є датами часу. Приклад:
trait Animal {
fn speak(&self);
}
struct Cat;
impl Animal for Cat {
fn speak(&self) {
println!("meow");
}
}
dbg!(size_of::<&Cat>());
dbg!(size_of::<&dyn Animal>());
Це друкує (з деяким очищенням):
size_of::<&Cat>() = 8
size_of::<&dyn Animal>() = 16
Знову ж таки, &Catмає лише 8 байт, оскільки Catце нормальний тип. Але dyn Animalє об’єктом ознаки і тому має динамічний розмір. Таким чином, він &dyn Animalмає 16 байт.
У випадку об'єктів ознак додатковими даними, що заповнюють літній час, є вказівник на vtable (vptr). Я не можу повністю пояснити поняття vtables і vptrs тут, але вони використовуються для виклику правильної реалізації методу у цьому контексті віртуальної диспетчеризації. Vtable - це статична частина даних, яка в основному містить лише покажчик функції для кожного методу. При цьому посилання на об'єкт ознаки в основному представляється як:
struct TraitObjectRef {
data_ptr: *const (),
vptr: *const (),
}
(Це відрізняється від С ++, де vptr для абстрактних класів зберігається в об'єкті. Обидва підходи мають переваги та недоліки.)
Спеціальні переходи на літній час
Насправді можна створити власні датські часові пояси, маючи структуру, де останнє поле - літній час. Однак це досить рідко. Одним з яскравих прикладів є std::path::Path.
Посилання або вказівник на власний перехід на літній час також є показником жиру. Додаткові дані залежать від виду літнього часу в структурі.
Виняток: зовнішні типи
У RFC 1861 ця extern typeфункція була введена. Зовнішні типи - це також літній час, але вказівники на них не є показником жиру. Або точніше, як висловлюється RFC:
У Rust вказівники на DST містять метадані про об’єкт, на який вказують. Для рядків та фрагментів це довжина буфера, для об’єктів ознак це vtable об’єкта. Для зовнішніх типів метадані просто (). Це означає, що покажчик на тип extern має такий самий розмір, як і usize(тобто він не є "жировим покажчиком").
Але якщо ви не взаємодієте з інтерфейсом C, вам, мабуть, ніколи не доведеться мати справу з цими зовнішніми типами.
Вище ми бачили розміри незмінних посилань. Покажчики жиру працюють однаково для змінних посилань, незмінних необроблених покажчиків та змінних необроблених покажчиків:
size_of::<&[u32]>() = 16
size_of::<&mut [u32]>() = 16
size_of::<*const [u32]>() = 16
size_of::<*mut [u32]>() = 16