In Rust, we can use .iter() on various collection to create a non-owning iterator which returns references on a collection like Vec. We can also use .into_iter() to create a consuming iterator which then returns values moved out of the collection. There is no trait for .iter() like there is for .into_iter(), but we can achieve the same thing by calling .into_iter() on a reference to the collection.
For example, this function compiles fine:
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
}
I want to make this function generic. I want it to accept not just a Vec of i32, but also any other collection of i32 that happens to implement IntoIterator<Item=i32>.
Doing that seems simple enough, yet the following generic function no longer compiles.
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
}
Compilation fails with the following error:
| 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
I don't quite understand this part of the error:
move occurs because value has type `T`, which does not implement the `Copy`
I'm not trying to copy a value of type T. I'm trying to copy a value of type &T, i.e. a reference to T, not T itself. I thought you could copy non-mutable references without issues. Why would it be required for T, not &T, to implement Copy?
In the context of a generic function, the only things exist for the type are from the bounds. If you specify T: IntoIterator<Item = i32>, then only T implements IntoIterator, &T does not. Of course, autoderef kicks in, dereferencing the reference but trying to move the value out of it.
If you want to specify that &T implements IntoIterator, the way to do that is as follows:
fn test_generic<T>(vec: T)
where
T: IntoIterator<Item = i32>,
for<'a> &'a T: IntoIterator<Item = &'a i32>,
{
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With