在Rust中,我们可以在不同的集合上使用.iter()
来创建一个非所有者迭代器,它返回一个集合上的引用,比如Vec。我们也可以使用.into_iter()
来创建一个消费迭代器,然后返回从集合中移出的值。.iter()
没有.into_iter()
那样的trait,但是我们可以通过在对集合的引用上调用.into_iter()
来实现同样的事情。
例如,此函数编译良好:
fn test_vec(vec: Vec<i32>) {
let i1 = (&vec).into_iter(); // create a non-owning iterator
let i2 = (&vec).into_iter(); // create another one
let i3 = vec.into_iter(); // create an owning iterator which consumes the collection
// no more non-owning iterators can be created
}
我想让这个函数成为泛型函数,我想让它不仅接受i32的Vec,而且接受i32的任何其他集合,这些集合碰巧实现了IntoIterator〈Item=i32〉。
这样做看起来很简单,但是下面的泛型函数不再编译。
fn test_generic<T: IntoIterator<Item = i32>>(vec: T) {
let i1 = (&vec).into_iter(); // create a non-owning iterator
let i2 = (&vec).into_iter(); // create another one
let i3 = vec.into_iter(); // create an owning iterator which consumes the collection
// no more non-owning iterators can be created
}
编译失败,出现以下错误:
| let i1 = (&vec).into_iter(); // create a non-owning iterator
| ^^^^^^^-----------
| | |
| | value moved due to this method call
| move occurs because value has type `T`, which does not implement the `Copy` trait
|
note: this function takes ownership of the receiver `self`, which moves value
我不太理解这部分错误:
move occurs because value has type `T`, which does not implement the `Copy`
我不是要复制类型T的值。我是要复制类型**&T**的值,即对T的引用,而不是T本身。我以为你可以毫无问题地复制不可变的引用。为什么需要T而不是&T来实现Copy?
2条答案
按热度按时间r3i60tvu1#
在泛型函数的上下文中,该类型唯一存在的东西来自边界。如果指定
T: IntoIterator<Item = i32>
,则只有T
实现IntoIterator
,&T
不实现。当然,autoderef会启动,解引用引用引用,但试图将值移出引用。如果要指定
&T
实现IntoIterator
,方法如下:nkhmeac62#
您编写的约束是
vec
必须为IntoIterator
。(比如Vec
),它有.iter()
方法来获取非消耗迭代器,但 * 也 * 任何其他迭代器。如果vec
是一个流,其中数据被消耗,然后立即被抛出到void中,你的签名是完全匹配的(这是i32
上的迭代器),但是接受一个对你的流的引用并不能保证你可以迭代i32
上的引用:不管你对接收到的整数做了什么,你调用了流并丢失了“先前”的值。有几种解决方案:
Vec
或类似的东西中,然后对一个已知的数据结构做任何你想做的事情,或者在调用迭代器的地方做一些更好的事情,然后根据你的需要递增地建立一个缓存)。Vec
、切片、数组还是其他什么),你需要在签名中表达出来: