在幕后,Rust 中的向量是通过引用还是值返回的?

问题描述 投票:0回答:2

我正在尝试了解 Rust 内存的来龙去脉。当在函数内部创建向量然后返回时,是返回引用还是复制整个向量?

示例:

use std::io;

fn line_to_ints() -> Vec<u32> {
    let mut line = String::new();

    io::stdin()
        .read_line(&mut line)
        .expect("Failed to read line");

    return line
        .split(" ")
        .map(|x| x.parse().expect("Not an integer!"))
        .collect();
}

对于所有其他非原始数据类型,这里的返回行为也相同吗?

有没有办法返回对函数中创建的变量的引用?,我想更多地了解幕后发生的事情。该问题的答案并没有明确说明是否创建向量然后将其复制到新位置,或者返回指针的所有权我理解向量是在堆上创建的,所以我想涉及到一个指针。

memory rust
2个回答
10
投票

是返回的参考

不。不可能是因为一旦函数结束就没有没有什么可以引用有什么方法可以返回对函数中创建的变量的引用吗?

对此进行了详细介绍。

整个向量都被复制了

是的,但可能不是你的意思。 A

Vec
基本上定义为

struct Vec<T> {
    capacity: usize,
    length: usize,
    data: *mut T,
}

从语义上讲,这 3 个指针大小的字段已从函数“移动”到调用者。向量包含的 N 个元素不会被复制。 在实现方面,编译器/优化器可以从一大堆技巧中进行选择:

实际上复制所有三个字段
  • 传入一个秘密的可变引用并让函数直接写入它
  • 在调用函数的地方内联函数
  • 执行死代码删除,并且从一开始就不要调用该函数
  • 可能还有其他人...
  • 了解它选择哪个的唯一方法是查看 MIR / LLVM IR / 程序集。

对于所有其他非原始数据类型,这里的返回行为也相同吗?

是的。 Rust 的数据类型都被同等对待。原始与非原始对于语言的语义来说没有任何意义。

另请参阅:

    我可以在 Rust 中有效地按值返回对象吗?
  • 实例构建效率低下?
  • 使用 box 关键字和 Box::new 有什么区别?
  • Rust 中的移动语义是什么?
  • Rust 如何提供移动语义?

0
投票

Vec 结构本身,这是一个固定大小的结构,由一个指针和两个指针大小的整数组成,分别表示大小和容量。所以它的大小是三个指针(32 位上 12 个字节,64 位上 24 个字节)。
  1. 堆上的一块内存,存储向量的元素。
  2. 当返回 Vec 时,vec 结构本身在逻辑上按值“移动”。堆上的内存块未受影响。

Rust 语言没有具体指定 vec 结构如何移动。然而,在大多数情况下,rustc 遵循目标平台的标准调用约定。 amd64 和 aarch64 都在寄存器中返回小结构,但它们对“小结构”的正常定义是大小最多为两个指针的结构。除此之外,他们转向了“大型结构”的策略,即用指针替换它们。

为了演示这一点,我在 godbolt 上构建了以下代码。

#[inline(never)] pub fn vecofints(v: Vec<i32>) -> Vec<i32> { return v; }

在 x86-64 上这导致了。

example::vecofints::h4b8b50ca2c3019a3: mov rax, rdi mov rcx, qword ptr [rsi + 16] mov qword ptr [rdi + 16], rcx movups xmm0, xmmword ptr [rsi] movups xmmword ptr [rdi], xmm0 ret

在这种情况下,我们可以看到,参数和结果都作为指针传递,指向参数的指针在 rsi(第一个参数传递寄存器)中传递,指向结果的指针在 rdi(第二个参数传递寄存器)中传递。参数传递寄存器)。

在 aarch64 上这导致了。

example::vecofints::hee34a085ad28128f: ldr q0, [x0] ldr x9, [x0, #16] str q0, [x8] str x9, [x8, #16] ret

这非常相似,除了 aarch64 没有在参数传递寄存器之一中传递返回值的隐藏指针,而是有一个专用寄存器用于此目的。

可以实现一种类似 vec 的类型,其中 Vec 结构本身只有一个大小的指针,其中有一些通常具有“thinvec”之类的名称。

© www.soinside.com 2019 - 2024. All rights reserved.