Let's say that I have vector and I want just keep the even elements. I would need to used cloned()
and filter()
. For example:
fn main() {
let my_vec: Vec<i32> = vec![1,2,3,4];
let my_vec_1: Vec<i32> = my_vec.iter().cloned().filter(|&x| x % 2 == 0).collect();
println!("{:?}", my_vec_1);
let my_vec_2: Vec<i32> = my_vec.iter().filter(|&x| x % 2 == 0).cloned().collect();
println!("{:?}", my_vec_2);
}
Both approaches work. Using cloned()
after filter()
seems a little bit more efficient. Because then I don't have to convert all elements of the iterator from &T
to T
, but only the ones that have been filtered. In my example that's half the elements.
However, I seem to see cloned()
applied before filter()
. Here is one example: method.inspect
I thought that maybe .cloned()
has to be used before for types that don't implement Copy
trait, but it does not seem to be the case: nested vec example. Also, because filter uses FnMut(&Self::Item)
, I don' think that should be a problem.
Are there advantages to using cloned()
before filter()
? Is this more of a stylistic issue? If so, is there preferred style?
This is an alternative to Matthieu M.'s answer.
When you have small, Copy
elements, you should Clone
them as soon as possible. Cloning is nearly always free in these cases, but I have seen extra indirection confuse the optimizer. When you call iter
on a container of integers, cloned
should nearly always be the one to follow it unless you can merge it into the next call, eg. by an extra dereference in a call to map
.
So in the case given, using cloned
early is entirely sensible. It's true that this is a micro-optimization, but it's so easy to do and often makes the types simpler to work with, so I see no downsides to doing it.
In the future, copied
will likely become available as the preferred way to handle this.
When working with non-Copy
types, where Clone
might not be so cheap, delaying cloning is a much better default.
This is not a matter of style.
The example of inspect
is made to show-case inspect
, that is all. It uses .cloned
in an arguably silly way, but cloned
was probably chosen because of its easy to understand semantic so as to create an easy to understand "complex iterator sequence".
So, .cloned()
before or after .filter(...)
? As you mention, unless cloning is necessary for filtering (which would be surprising) the rule of thumb will be to clone after so as to minimize the number of cloned elements.
No style here, just a pragmatic performance assessment.
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