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

5

我正在尝试学习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();
}

这里的返回行为对于所有其他非基本数据类型也是相同的吗?
有没有办法返回在函数中创建的变量的引用?不同,我想更多地了解底层发生了什么。那个问题的答案并没有清楚地说明向量是否被创建然后复制到新位置,或者指针的所有权是否被返回。我知道向量是在堆上创建的,所以我想象一个指针是涉及其中的。

习惯用语化的Rust在代码块结束处不使用return关键字。相反,您可以省略return和分号。 - Shepmaster
1
“返回的是引用还是整个向量被复制?”这取决于您所说的整个向量是什么意思,您的函数创建一个向量并将所有权交给调用者,这是一种移动操作,不用担心,这应该很好,没有任何性能问题。 - Stargateur
问题已更新 - tnibbles
1个回答

9

返回的是一个引用

不可以,因为一旦函数结束,就没有任何需要引用的内容。这在Is there any way to return a reference to a variable created in a function?中有详细讲解。

整个向量是否被复制

是的,但可能不是你想要的方式。一个Vec基本上是这样定义的:

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

从语义上讲,这3个指针大小的字段是从函数移动到调用者的。向量包含的N个元素不会被复制。
在实现上,编译器/优化器可以从一大堆技巧中选择:
- 实际上复制所有三个字段 - 传递一个秘密的可变引用,并让函数直接写入它 - 内联函数在调用它的地方 - 执行死代码删除,从未调用该函数 - 可能还有其他方法...
唯一知道它选择哪个方法的方法是查看MIR / LLVM IR /汇编代码。
“这里的返回行为对于所有其他非原始数据类型也是相同的吗?”
是的。Rust的数据类型都是相同处理的。原始和非原始的区别对于语言的语义没有任何意义。
另请参见:

谢谢您的解释。有了这些额外信息,我可以理解链接的问题了。 - tnibbles

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接