rust - 当函数引用变量作为参数时,函数的堆栈到底分配了什么?

标签 rust

我们读到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 种特殊情况:

  1. 切片的情况。 &[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/

    相关文章:

    rust - 使用 Hyper 发出请求时如何设置 User-Agent header ?

    rust - 如何使用相同的可变借用调用 serde_json::to_writer 两次?

    rust - Impl Into<B> 所有类型的 impl Into<A> 特性

    generics - 如何在特征边界中指定 `std::ops::Mul` 的预期结果?

    rust - 为什么这两个结构受生命周期影响的方式不同

    scala - 不能将 futures-util crate 与 Actix 一起使用,因为特征 Future 未实现

    rust - 如何使用生命周期边界来解决 "reference must be valid for the static lifetime"

    data-structures - 如何在不需要分配给新变量的情况下为链表实现前置?

    rust - 为什么向 trait 添加泛型类型会影响 trait 对象和关联类型的生命周期?

    unit-testing - 为什么 `assert_eq` 和 `assert_ne` 存在,而简单的 `assert` 就足够了?