Iterator references with Vulkano

Hi!

I'm currently learning Rust. My current understanding is that:

let b = [1, 2, 3, 4];
for a in b {
    foo(a);
}
// b is now owned by the for-loop, it can't used

If we want to be able to use the iterator after the loop, we must use an iterator reference:

for a in &b {
    foo(a);
}
// we can still use b here, because the loop only owned a reference

I'm trying to use this pattern with Vulkano. My code looks like:

let mut physical_devices = PhysicalDevice::enumerate(&instance);
for physical_device in physical_devices {
    println!(…);
}
let selected_physical_device = physical_devices.next().expect("Couldn't select a graphics card.");

I understand why this doesn't compile: physical_device is owned by the loop, and therefore can't be used afterwards.

However, if I replace the loop by &physical_device, I get the error:

19  |         for physical_device in &physical_devices {
    |                                -^^^^^^^^^^^^^^^^
    |                                |
    |                                `&PhysicalDevicesIter<'_>` is not an iterator
    |                                help: consider removing the leading `&`-reference
    |
    = help: the trait `Iterator` is not implemented for `&PhysicalDevicesIter<'_>`
    = note: `Iterator` is implemented for `&mut vulkano::instance::PhysicalDevicesIter<'_>`, but not for `&vulkano::instance::PhysicalDevicesIter<'_>`
    = note: required because of the requirements on the impl of `IntoIterator` for `&PhysicalDevicesIter<'_>`

Since this references to this type don't implement Iterator, how can I loop over it without losing ownership of the array?

Wouldn't for physical_device in &mut physical_devices work? The Iterator trait has a blanket impl for &mut impl Iterator, and the compiler itself proposed this exact solution in the error message.

It does work. Where did you find the error message that mentioned it?

for physical_device in physical_devices gives the error message:

19  |         let mut physical_devices = PhysicalDevice::enumerate(&instance);
    |             -------------------- move occurs because `physical_devices` has type `PhysicalDevicesIter<'_>`, which does not implement the `Copy` trait
20  |         for physical_device in physical_devices {
    |                                ----------------
    |                                |
    |                                `physical_devices` moved due to this implicit call to `.into_iter()`
    |                                help: consider borrowing to avoid moving into the for loop: `&physical_devices`
...
27  |         let _physical_device = physical_devices.next().expect("Couldn't select a graphics card.");
    |                                ^^^^^^^^^^^^^^^^ value borrowed here after move
    |

for physical_device in &physical_devices gives the error message in the original post, which doesn't mention &mut either.

Possibly useful clarification: The thing that is going on in your original sample for a in &b { foo(a) } is not making a reference to an iterator, it's making an iterator from a reference to a collection. By convention, references to collections often implement IntoIterator so as to iterate over references to their contents — that's the behavior you're invoking here, specifically this implementation in the std library:

impl<'a, T, const N: usize> IntoIterator for &'a [T; N]

as opposed to the non-reference version which moves/consumes the input array:

impl<T, const N: usize> IntoIterator for [T; N]

The difference I want to point out is that it's possible to iterate over a collection without mutating it (which you conventionally invoke using .iter() or (implicitly) the above IntoIterator implementation), but an iterator is always mutated by iterating and thus requires at least &mut access — and no longer has the elements that are iterated over, whether you use it as owned or &mut.

You posted it.

It does.

note: `Iterator` is implemented for `&mut vulkano::instance::PhysicalDevicesIter<'_>`,
but not for `&vulkano::instance::PhysicalDevicesIter<'_>`

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.