r/learnrust • • 4d ago

More concise way to write `self.some_vec.iter().copied()` ?

In a &self method, when I have a Vec of Copyable data and I want to iterate over owned values, either I iterate over references and dereference inside the loop body (I don't really like this style), or I have to do this iter().copied() boilerplate. Not a big deal, but is there some syntax that I'm missing ?

Edit: toy code

struct Foo {
    some_vec: Vec<i32>,
}

impl Foo {
    fn iterate(&self) {
        for v in self.some_vec.iter().copied() {
            do_some_stuff(v);
        }
    }
}

fn do_some_stuff(v: i32) {
    ....
}
6 Upvotes

18 comments sorted by

14

u/djvbmd 4d ago

Not sure why you dislike this style; it's the most concise / readable to me:

for v in self.some_vec.iter() {
    do_stuff(*v);
}

I'll move the deref to the pattern deconstruction in the for loop sometimes, though I don't feel like it's as explicit:

for &v in self.some_vec.iter() {
    do_stuff(v);
}

The version you're trying to get away from is probably the most explicit of all, but -- I agree -- annoying to write repeatedly. AFAIK there isn't any other ready-made syntax to do what you're doing.

1

u/jesseschalken 1d ago

You also don't need the .iter() here, for a in b calls b.into_iter() which is defined on &Vec<T> to yield &T.

7

u/RazorBest 4d ago

I'm curious: is there a real life use case for wanting to copy a value, and cloneing it would have a different effect?

I know it's possible to have something like: ```

[derive(Copy)]

struct A(i64);

impl Clone for A {     fn clone(&self) -> Self {         A(self.0 +1)     } } ```

But I wouldn't imagine a case where someone would ever do such a thing.

8

u/Pleasant-Couple6236 4d ago

Not really, I think the rationale for having two distinct traits for this is that Copy should only be (can only be?) used for very fast copies that only touches the stack, copying individual ints, pointers etc, while using Clone signals it might be performing a deep copy, allocating potentially large new data structures on the heap.

3

u/garagedragon 3d ago edited 3d ago

Copy means specifically that creating a copy can be done by directly copying bits with no additional logic, which means as a side effect the original value can still be reused and isn't consumed by moves. It is usually, but not guaranteed to be fast, because very large structures can still be Copy if they're plain data, like say, [u8; 4096]. IIRC you must derive Copy, you can't manually implement it, so all the fields of a copy type are also necessarily Copy. (It is not just a marker trait on top of Clone in the way Eq is on PartialEq) Copying is still deep, if you can do it at all, since it'll also copy all fields by value. It's also not intrinsically tied to stack/heap, you can copy values to and from the interior of a Box even though the Box handle itself is not Copy because it needs to ensure it's pointer is unique.

Clone is conceptually the same operation, but it's allowed to run arbitrary code. There's no actual requirement that Clone do the same thing as Copy if the latter is implemented, but IMO there's no sensible reason you'd have a Copy type not simply derive Clone as well rather than implement it manually.

3

u/The_Coalition 3d ago

Copy is always a byte-for-byte copy of the original, so it's always fast. It's not a marker type over Clone - you also can't force a non-copyable type to implement Copy, not even with unsafe.

4

u/buwlerman 4d ago

I'm surprised that that's possible. I'd have imagined there was some compiler magic that required the derived Clone impl. At least there's a clippy warning for it.

3

u/Aaron1924 4d ago

How about this? for v in &self.some_vec { do_some_stuff(*v); }

2

u/tanoshikuidomouyo 4d ago edited 4d ago

You may be missing that 'for' introduces a pattern where you can deconstruct references.

So in your example: for &v in &self.some_vec { ... }

Excuse the formatting

1

u/LetsGoPepele 3d ago

Yeah that's it. Thank you

3

u/This_Growth2898 4d ago

Are you looking for into_iter()?

2

u/LetsGoPepele 4d ago

No, because I only have a shared reference &self, so I cannot move some_vec out of &self by calling into_iter()

1

u/This_Growth2898 4d ago

Also,

self.some_vec.iter().for_each(|&i|do_some_stuff(i));

-1

u/This_Growth2898 4d ago

When I've answered, you didn't say you have such a restriction. Next time, please, try to describe your situation in more detail to get better answers.

.copied() is there for a reason, and it looks like this is an exact situation when you need it. You have only borrowed values, and you need to copy them; that's what .copied() is about.

1

u/LetsGoPepele 3d ago

Well... I did...

In a &self method

But yeah I agree my first post wasn't very clear. Thank you for your replies.

1

u/Otherwise-Flower903 4d ago

What’s your aversion to dereferencing inside the loop? 

1

u/LetsGoPepele 3d ago

I don't know, it just feels weird to me

1

u/Giocri 4d ago

Just use .cloned() if you ever end up with a type that has different behaviors for clone and copy you should just break the knees of whoever made It. Performance wise should'nt be a problem i'd expect the compiler to generate identical assembly for the two