问题描述
我已经在多个上下文中阅读过术语胖指针",但我不确定它的确切含义以及何时在 Rust 中使用.指针似乎是普通指针的两倍大,但我不明白为什么.它似乎也与 trait 对象有关.
I've read the term "fat pointer" in several contexts already, but I'm not sure what exactly it means and when it is used in Rust. The pointer seems to be twice as large as a normal pointer, but I don't understand why. It also seems to have something to do with trait objects.
推荐答案
术语胖指针"用于引用对动态大小类型 (DST) – 切片或特征对象的引用和原始指针. 胖指针包含一个指针和一些使 DST完整"的信息.(例如长度).
The term "fat pointer" is used to refer to references and raw pointers to dynamically sized types (DSTs) – slices or trait objects. A fat pointer contains a pointer plus some information that makes the DST "complete" (e.g. the length).
Rust 中最常用的类型不是 DST,但在编译时具有已知的固定大小.这些类型实现了 Sized
trait.即使是管理动态大小的堆缓冲区的类型(如 Vec
)也是 Sized
,因为编译器知道 Vec 的确切字节数.
实例将占用堆栈.Rust 目前有四种不同的 DST.
dbg!(size_of::<&u32>());
dbg!(size_of::<&[u32; 2]>());
dbg!(size_of::<&[u32]>());
This prints (with some cleanup):
size_of::<&u32>() = 8
size_of::<&[u32; 2]>() = 8
size_of::<&[u32]>() = 16
struct SliceRef {
ptr: *const u32,
len: usize,
}
Trait 对象 (dyn Trait
)
当使用 trait 作为 trait 对象(即类型擦除、动态调度)时,这些 trait 对象是 DST.示例:
Trait objects (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>());
This prints (with some cleanup):
size_of::<&Cat>() = 8
size_of::<&dyn Animal>() = 16
同样,&Cat
只有 8 字节大,因为 Cat
是普通类型.但是 dyn Animal
是一个 trait 对象,因此可以动态调整大小.因此,&dyn Animal
大小为 16 字节.
struct TraitObjectRef {
data_ptr: *const (),
vptr: *const (),
}
(这与 C++ 不同,C++ 中抽象类的 vptr 存储在对象中.两种方法都有优点和缺点.)
实际上可以通过使用最后一个字段是 DST 的结构来创建自己的 DST.不过,这种情况相当罕见.一个突出的例子是 std::path::Path
.
自定义 DST 的引用或指针也是一个胖指针.附加数据取决于结构内的 DST 类型.
在 RFC 1861 中,引入了 extern type
功能.Extern 类型也是 DST,但指向它们的指针不是胖指针.或者更准确地说,正如 RFC 所说:
In RFC 1861, the extern type
feature was introduced. Extern types are also DSTs, but pointers to them are not fat pointers. Or more exactly, as the RFC puts it:
在 Rust 中,指向 DST 的指针携带有关所指向对象的元数据.对于字符串和切片,这是缓冲区的长度,对于 trait 对象,这是对象的 vtable.对于 extern 类型,元数据只是 ()
.这意味着指向 extern 类型的指针与 usize
具有相同的大小(即,它不是胖指针").
但如果您不与 C 接口交互,您可能永远不必处理这些 extern 类型.
But if you are not interacting with a C interface, you probably won't ever have to deal with these extern types.
在上面,我们已经看到了不可变引用的大小.胖指针对于可变引用、不可变原始指针和可变原始指针的作用相同:
Above, we've seen the sizes for immutable references. Fat pointers work the same for mutable references, immutable raw pointers and mutable raw pointers:
size_of::<&[u32]>() = 16
size_of::<&mut [u32]>() = 16
size_of::<*const [u32]>() = 16
size_of::<*mut [u32]>() = 16
这篇关于什么是“胖指针"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!