当一个函数引用一个变量作为参数时,究竟将什么分配给该函数的堆栈?

ayu*_*har 2 rust

我们在所有权中阅读了函数如何将其参数数据保留在堆栈中。在原始类型的情况下,这可能是一个值,或者是指向堆中驻留的数据的指针。现在,当引用某个东西时,该参数如何在堆栈中表示?

Opt*_*ach 5

在内部,引用(即&'a T基本上只是一个指针)。区别在于您Rust的静态编译规则保证了内存的安全性。同样,您在本章中刚刚阅读的规则。当您将参数传递给时,说一个具有如下签名的函数:

struct UnitBar(i32);
fn foo(data: &UnitBar);
Run Code Online (Sandbox Code Playgroud)

您这样称呼它:

struct UnitBar(i32);
fn main() {
    let bar = UnitBar(0); //Sizeof bar is sizeof i32
    foo(&bar);
}
Run Code Online (Sandbox Code Playgroud)

UnitBar在这种情况下,Rust将分配一个4字节的a 。然后,它将分配一个指向的指针bar,该指针的大小与计算机中的本机指针大小相同,或更习惯上与usizein rust 相同。请注意,在内存级别,指针和引用之间没有区别。在静态编译级别或您的代码中,会进行静态编译时检查,以确保您的代码遵循rust的规则。从这里开始,data参数in fn foo将表示为内存中的指针。每次传递给另一个函数或作用域时,这都不会复制它指向的数据。

尽管不能保证看起来像这样,但由于编译器可以在内存中四处移动以生成更高效的程序,因此这几乎是它的工作方式。


附带说明一下,有3种特殊情况:

  1. 切片的情况。&[T]将需要两个“指针长度”来存储。为什么?因为a &[T]是一种特殊类型,所以其中包含a *const T和a usize。这是c的等效项:
struct SliceReference {
    *const T data;
    size_t length;
}
Run Code Online (Sandbox Code Playgroud)
  1. 另一种(类似情况)是&str。这本质上是a &[u8],因此它也遵循上面的内存模型,但是向您保证它包含的所有字符(即,存储在其中的字节配置)都是UTF-8。
  2. 这是最后一种情况,其中存在特征对象。即,&dyn std::fmt::Debug。对于c / c ++程序员,其大小再次为2 usize或2 size_ts。第一个指针指向数据,第二个指针指向vtable,其中存储了每个函数各自的函数签名。

请注意,以上所有内容均与&T内存中的内容基本相同:

Option<&T>     -|
Box<T>          |
Rc<T>           - These all have the same size as `&T`
Arc<Mutex<T>>   |
struct Foo(&T) -|
Run Code Online (Sandbox Code Playgroud)

作为编辑,这里证明它们都是相同的大小。