Reputation: 88398
Here is a small Rust script (yes, I know unwrap
is discouraged but it works for this short example):
fn main() {
let args = std::env::args();
let word = args.last().unwrap();
println!("Last argument is {}", word);
}
I see from the Rust documentation that
std
is a crateenv
is a module within crate std
args
is a function within the moduleArgs
, a structArgs
implements the traits Iterator
and ExactSizeIterator
However, neither Args
nor Iterator
nor ExactSizeIterator
, as far as I can tell from the documentation, ever defines a method called last
! Args
defines nothing on its own, Iterator
just defines next
and size_hint
, and ExactSizeIterator
defines len
.
So why does this script work? How is last
allowed to be called for an Args
value? Is the documentation lacking or am I missing something?
Upvotes: 1
Views: 108
Reputation: 431279
Sometimes you need to work both directions in the documentation. Doing a search for last
will lead you to IteratorExt::last
:
fn last(self) -> Option<<Self as Iterator>::Item>
IteratorExt
is defined as:
pub trait IteratorExt where Self: Iterator {
// ...
}
This is an extension trait - a collection of methods that are all applied to another trait. It's done this way to help preserve object safety, as some of these methods require consuming the argument, which means that the argument has to have a known size. The trait has a blanket implementation to get it to apply:
impl<I> IteratorExt for I where I: Iterator
However, there's been some work recently to reduce the number of extension traits, as it was realized that you can simply add a bound of Sized
to certain methods. It's possible some of that might apply to IteratorExt
and they will move back to Iterator
proper.
Upvotes: 2
Reputation: 2249
The last
method comes from the IteratorExt
trait, which defines methods for all iterators by having a impl<I> IteratorExt for I where I: Iterator
blanket implementation.
These methods are in scope, because the trait IteratorExt
is imported in the prelude
.
Upvotes: 4