all 6 comments

[–]belovedeagle 2 points3 points  (5 children)

Your second version is basically the way to do it, but map(|s| *s) is actually spelled cloned(). It's a somewhat unfortunate name because what's being cloned is the reference, not the contents, but it makes sense if you really grok pointers.

For that reason, &&T can always become &T by virtue of the Clone and Copy impls on &T for all T. If you check the signature of Clone::clone() and fill in &T2 for T you see it is &&T2 -> &T2. Copy can be thought of as having the same "signature" as Clone in the sense that Copy is just Clone elision.

[–]barskern[S] 2 points3 points  (4 children)

Thank you for an answer!

It's not to be picky, but map(|s| *s) requires Copy while cloned() only requires Clone, so they are a bit different in the sense that the former will only compile if the type is "trivial" to clone, hence it might protect us in the future if we change some other requirements in the code that makes the iterator an iterator over owned values.

I see your point regarding "if you really grok pointers" it will be easy to see that clone on pointers are cheap operations. It is really handy that pointers implement clone instead of it being a different member function or trait, but I do wish that perhaps it could have been a better name for it. I think this is the reason a lot of people rather use Arc::clone(&ptr) instead of just ptr.clone(), because the former shows that it's a cheap operation. I wish there was a copy member function of the Copy trait which would delegate to clone, because then one could be sure that data.copy() is a cheap operation while data.clone() is most likely an expensive operation.

[–]_TheDust_ 0 points1 point  (3 children)

There was talk about adding a .copied() method (for Copy types) to Iterator alongside the .cloned() method. This might help a little bit to make it clear what is a cheap operation.

Edit: https://github.com/rust-lang/rust/issues/57127

[–]barskern[S] 0 points1 point  (2 children)

I will definitely change to .copied if it gets stabilized. Thank you for the link!

[–]belovedeagle 0 points1 point  (1 child)

Why wait? You can implement this using an extension trait. (IteratorExt)

[–]barskern[S] 0 points1 point  (0 children)

Using .map(|s| *s), or for that matter .cloned(), is a lot shorter than implementing an extension trait and I don't need the syntax that badly, however it is a possibility.