简体   繁体   中英

Advantages of pass-by-ref/val with impl IntoIterator<Item = impl AsRef<str>>

In Rust, I often see functions accepting impl IntoIter<...> iterators, eg

pub fn foo(
    args: impl IntoIterator<Item = impl AsRef<str>>,
) -> usize {
    // any kind of processing goes here - like this, but could be totally different
    args.into_iter().map(|s| s.as_ref().len()).sum()
}

If a caller has the ownership of some collection, eg a Vec , it could call foo in two ways (both compilable):

foo(args);
// or
foo(&args);

Are there any costs associated with pass-by-value in a case where a function can work with either? I tried comparing generated assembly, and the referenced version does look longer, but I don't have sufficient assemby knowledge to evaluate which is actually better.

The difference is the type inferred by impl IntoIterator .

The Owned value ( foo(args) ) generate the struct std::vec::IntoIter , that simply "pop" values from the Vec.

The Borrowed value ( foo(&args) ) generate the type std::slice::Iter<'_, &str> , this one is just a slice that produces value by returning the first element, and advance the slice to the next position.

The difference is the second case having a extra de-reference from the first. I don't now why the assembly code generated from each case is so different, and life is too short to be spent analyzing x86_64 assembly:)

But you can notice that the compiled code for armv7 and i586 is basically the same in both cases. This seems to indicate that there is little difference in those two implementations, and this seems to be a strange optimization that the compiler make exclusively for the x86_64 architecture.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM