Why the `cycle()` method exists if `ChunksMut` is never `Clone?`

The ChunksMut in std::slice - Rust has the cycle method: Cycle in std::iter - Rust that works only when Self: Clone

However, ChunksMut does not implement Clone, therefore I cannot do this:

fn main() {
    let a = &[1,2,3,4,5,6];
    let mut chunks = a.chunks_mut(2);
    let cycle = chunks.cycle();
    for c in cycle {
        
    }
}

Why the cycle() method exists if ChunksMut is never Clone?

cycle() is defined on the Iterator trait, not on ChunksMut. As for why it is there - well, because for most cases there's a sensible default implementation in terms of next and clone, and there's no need to duplicate it on every iterator possible.

1 Like

do you see a way to iterate over ChunksMut? I wanted to do something like this:

[1,2,3,4,5,6,7,8,9]

then iterate mutably like this:

&mut 1, &mut 4, &mut 7, &mut 2, &mut 5, &mut 8, &mut 3, &mut 6, &mut 9

If I could cycle over ChunksMut it would be easy but apparently I can't.

I think the question here might by why the compiler complains about "trait bounds not satisfied" instead of "no method named 'cycle' found".

But I'm not sure, maybe that interpretation is totally off.


In any case, the answer to this question is: the compiler doesn't really have an understanding that implementing Clone for ChunksMut is neither something you can do nor something the standard library will ever do. There are comparable scenarios where the missing bound can be added by you or at least could be added upstream in the future. In such a setting, the cycle method might magically appear out of nowhere if it was previously considered not a method on ChunksMut at all; methods suddenly appearing like that seems undesirable, so it's better that it just is a method that exists in the first place, even if it's entirely uncallable, because the trait bounds can't ever be fulfilled.

That's hard to do in general, since compiler can't prove that such interleaved mutable references won't collide, and their collision is prohibited by Iterator interface.

This access pattern is possible using the ndarray crate:

fn main() {
    let a = &mut [1, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut matrix = ndarray::ArrayViewMut::from_shape((3, 3), a).unwrap();
    let cycle = matrix.columns_mut().into_iter().flatten();
    for c in cycle {
        println!("value: {} -> {}", c, *c * 10);
        *c = *c * 10;
    }

    println!("final: {:?}", a);
}

(playground)

value: 1 -> 10
value: 4 -> 40
value: 7 -> 70
value: 2 -> 20
value: 5 -> 50
value: 8 -> 80
value: 3 -> 30
value: 6 -> 60
value: 9 -> 90
final: [10, 20, 30, 40, 50, 60, 70, 80, 90]
1 Like