在Rust中,是否可以遍历切片的值而不是引用?

42
当循环遍历结构体切片时,我得到的值是一个引用(这是可以的),但在某些情况下,我不得不在很多地方写上var作为(*var),这有点烦人。
有没有更好的方法来避免重新声明变量?
fn my_fn(slice: &[MyStruct]) {
    for var in slice {
        let var = *var;  // <-- how to avoid this?

        // Without the line above, errors in comments occur:

        other_fn(var);  // <-- expected struct `MyStruct`, found reference

        if var != var.other {
            // ^^ trait `&MyStruct: std::cmp::PartialEq<MyStruct>>` not satisfied
            foo();
        }
    }
}
2个回答

54
你可以通过解构模式旧链接)来删除引用。
//  |
//  v
for &var in slice {
    other_fn(var);
}

然而,这仅适用于“Copy”类型!如果您有一个没有实现“Copy”但实现了“Clone”的类型,您可以使用“cloned()”迭代器适配器;有关更多信息,请参阅Chris Emerson的答案

嗨,喜欢这个答案,但是我找不到这是如何在模式中进行“解构”(destructuring)的方法...也许我可以把它想象成函数参数中如何使用&...需要更多了解在模式前面使用&var的作用... - undefined
所以,如果它实现了Copy类型,那么根据Chris Emerson的回答,也可以这样做: for var in slice.iter().copied() { other_fn(var); } - undefined
1
@NateAnderson,你说得对,这就是模式解构的作用。而且,copied()的解决方案也是可行的。 - undefined

39
在某些情况下,如果可以使用可迭代对象,请直接迭代值,例如使用 Vec::into_iter()。 对于切片,您可以在迭代器上使用clonedcopied
fn main() {
    let v = vec![1, 2, 3];
    let slice = &v[..];
    for u in slice.iter().cloned() {
        let u: usize = u; // prove it's really usize, not &usize
        println!("{}", u);
    }
}

这取决于该项是否实现CloneCopy,但如果它没有实现的话,你可能确实需要引用。


1
这并不像Lukas的回答那样内存高效。此外,“slice”不是可变的,因此尽管迭代器可能已被消耗,但“slice”本身不需要克隆。 - Eli Sadoff
5
实际上,我们两个方案的结果可能会产生相同的优化后汇编代码。不是完整的切片或迭代器被克隆,而是每个被生成的元素被克隆。 - Lukas Kalbertodt
@LukasKalbertodt 你说得对。我也没有考虑到这个CloneCopy的问题,这个需要注意。 - Eli Sadoff
1
比被接受的答案更有价值,因为它提到了into_iter()。我真正需要知道的是与iter()的区别。 - Victor Sergienko
1
@VictorSergienko 在切片上使用 iter()into_iter() 是完全相同的:https://github.com/rust-lang/rust/blob/fd9ca0c25ec90f6ed156e6f0e950763ca5171f8a/library/core/src/slice/iter.rs#L23 - CLOVIS

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