我们在Ownership中读取函数如何将其参数数据保存在堆栈中。对于原始类型或指向驻留在堆上的数据的指针,这可能是一个值。现在,当参数是什么时,参数如何在堆栈中表示?
在内部,一个引用,即&'a T
基本上只是一个指针。不同之处在于,Rust
的静态编译规则保证了内存安全。就像你在那一章中读到的规则一样。当您将参数传递给时,例如具有如下签名的函数:
struct UnitBar(i32);
fn foo(data: &UnitBar);
你这么称呼它:
struct UnitBar(i32);
fn main() {
let bar = UnitBar(0); //Sizeof bar is sizeof i32
foo(&bar);
}
Rust会分配一个UnitBar
,在这种情况下是4个字节。然后,它将分配一个指向bar
的指针,该指针与计算机中的本机指针大小相同,或更加惯用于与生锈中的usize
相同的大小。请注意,指针和内存级别的引用之间没有区别。在静态编译级别或代码中,有静态编译时检查以确保您的代码遵循rust的规则。从这里开始,data
中的fn foo
参数将表示为内存中的指针。每次将数据传递给另一个函数或作用域时,它都不会复制它指向的数据。
虽然不能保证看起来像这样,因为编译器可以在内存中移动以生成更高效的程序,这几乎就是它的工作原理。
作为旁注,有3个特例:
&[T]
将采用两个“指针长度”来存储。为什么?因为&[T]
是一种特殊的类型,它包含*const T
和usize
。这是相当于这个的c:struct SliceReference {
*const T data;
size_t length;
}
&str
。这本质上是一个&[u8]
,所以它也遵循上面的内存模型,而是向你保证它包含的所有字符,即存储在其中的字节配置,都是UTF-8。&dyn std::fmt::Debug
。对于c / c ++程序员来说,这个大小又是两个usize
s或两个size_t
s。存在指向数据的第一指针,第二指针指向存储其各自功能的功能签名的vtable。请注意,以上所有内容都与内存中与&T
基本相同的内容相关:
Option<&T> -|
Box<T> |
Rc<T> - These all have the same size as `&T`
Arc<Mutex<T>> |
struct Foo(&T) -|
作为编辑,here证明这些都是相同的大小。