我们读到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 的指针,该指针的大小与计算机中的 native 指针相同,或者更惯用地与 rust 中的 usize 大小相同。这里请注意,指针和引用在内存级别没有区别。在静态编译级别或在您的代码中,有静态编译时检查以确保您的代码遵循 Rust 的规则。从这里开始,fn foo
中的data
参数将表示为内存中的指针。每次将其指向的数据传递到另一个函数或作用域时,不会复制它所指向的数据。
虽然不能保证看起来像这样,但由于编译器可以在内存中移动内容以生成更高效的程序,这几乎就是它的工作原理。
顺便说一句,有 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
或两个size_t
。第一个指针指向数据,第二个指针指向 vtable,其中存储了每个函数的函数签名。
请注意,上述所有内容都与内存中的 &T
本质上相同:
Option<&T> -|
Box<T> |
Rc<T> - These all have the same size as `&T`
Arc<Mutex<T>> |
struct Foo(&T) -|
作为编辑,here证明这些尺寸都是相同的。
关于rust - 当函数引用变量作为参数时,函数的堆栈到底分配了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55009498/