在Rust数组和向量上使用`for`循环

3

在Rust数组上使用for循环可以正常工作:

fn main() {
    let v = [1, 2, 3, 4, 5];
    for _ in v.into_iter() {}
    for _ in v.into_iter() {}
}

但是替换vec并不能编译:

fn main() {
    let v = vec![1, 2, 3, 4, 5];
    for _ in v.into_iter() {}
    for _ in v.into_iter() {}
}

错误信息:
use of moved value: `v`

我理解为什么这个程序不能与vec一起运行。但是为什么它可以与数组一起工作呢?我原本期望在数组示例中出现类似的错误,但它却没有报错。

3
你应该看到 move occurs because v has type Vec<i32>, which does not implement the Copy trait 的提示信息,这意味着 [i32; 5] 类型实现了 Copy 特征,所以你可以多次使用 into_iter 而不会移动。 - zenly
如果数组实现了Copy特质,那么每个for循环都会复制一次数组吗? - TSK
1
正如其他评论所建议的那样,只要所包含的数据类型也实现了Copy数组实现了 Copy。是的,对于每个for循环,数组都会被复制一次。 - kotatsuyaki
@kotatsuyaki 这是否意味着,即使使用v循环编译(其中v是一个数组),使用&v循环更有效率,因为避免了整个数组的复制? - TSK
@TSK 性能可能会相同。尽管代码中存在语义上的复制,但编译器完全能够消除它们。如有疑问,请随意使用诸如编译器资源管理器之类的工具来检查汇编输出。 - kotatsuyaki
1
@kotatsuyaki,我最近遇到了一个情况,其中memcpy成为性能瓶颈,经过调查发现确实是这个原因。但通常情况下这不是问题。在更改之前进行基准测试。 - Chayim Friedman
1个回答

4

添加细节:

  • 在Rust中,数组存储在堆栈上(类似于C/C++),因此它们可以被移动 -- 在Rust中是Copy() -- 这会对数据进行深拷贝,但这没问题,因为堆栈数据应该是轻量级的。

  • 在Rust中,向量存储在堆上(类似于C/C++),因此通常无法移动,通常必须进行深拷贝。

这里有一个很好的解释关于Copy()和Clone()之间的区别

原始回答:

正如另一位评论者提到的那样,Rust中的数组实现了Copy特质,因此可以多次按值传递,而向量类型必须显式地clone()才能实现相同的行为。

在Rust中,当函数的参数按值传递时,在除最后一次调用以外的所有调用中,编译器默认执行的是复制移动操作,而在最后一次调用中,它将转移原始数据的所有权,而不是进行复制/克隆。如果未实现Copy,编译器不会自动运行clone()

这里是关于Copy特质的文档:https://doc.rust-lang.org/std/marker/trait.Copy.html

数组的Copy实现文档可以在这里找到:https://doc.rust-lang.org/std/primitive.array.html#impl-Copy-for-%5BT%3B%20N%5D

这是一篇详细的好文章:https://colinsblog.net/2021-04-16-rust-ownership-comparisons/


没有.copy() - user3840170
好的发现。已修复以反映Copy重定向到Clone()。 - spdrman
链接到实现代码的地方可能会让程序员觉得需要浏览 Rust 源代码才能找到这些信息。预期的方式在这里,第一部分:https://doc.rust-lang.org/std/primitive.array.html 和这里:https://doc.rust-lang.org/std/primitive.array.html#impl-Copy-for-%5BT%3B%20N%5D - Finomnis

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