Intro
This blog is written in eng cus deref, ref and concept related to them could be super confusing when translation happens.
From top to bottom
fn from(args: impl Iterator<Item = String>) -> () {
let mut args = let mut args = args.peekable()
args.next();
while let Some(s) = args.next_if(|x: &String| x.starts_with("-")) {
match s.as_str() {
"-i" | "--ignore_case" => ignore_case = true,
_ => {
eprintln!("invalid parameter");
process::exit(1);
}
}
}
First of all, lets take a look at a simple case: we want to use iterator and walk through the vector. And for some reason, we want to check the next entry before advancing by calling fn next
. A simple way is to use the official wrapper for all the objects that implement trait Iterator → peekable
.
fn peekable(self) -> Peekable<Self>
All right, but why the f**k we should declare it as mutable? That’s cus the function next_if is defined as,
pub fn next_if(
&mut self,
func: impl FnOnce(&<I as Iterator>::Item) -> bool
) -> Option<<I as Iterator>::Item>
OK, now lets look into this function, this function takes a closure func, and throw true or false according to value of the next variable.
// official usage example of next_if
let mut iter = (0..5).peekable();
// The first item of the iterator is 0; consume it.
assert_eq!(iter.next_if(|&x| x == 0), Some(0));
Why |&x| x == 0
instead of |x| x == 0
?
To explain this question, we would have to throw another question: Do iterators return a reference to items or the value of the items in Rust?
So actually the input of the& closure here is of type &String
. And according to the definition func: impl FnOnce(&<I as Iterator>::Item)
, the input of closure is &<I as Iterator>::Item
. Guess what, we triggered a irrefutable matching, and the reason we use |&x| x == 0
is that, under this circumstance, x is dereferenced as int32
. Don’t take it for granted, cus this is for the sake of the realization of trait copy on int32
. So actually assert_eq!(iter.next_if(|x| *x == 0), Some(0));
is legal as well.
So, back to the starting point,
args.next_if(|x: &String| x.starts_with("-"))
Yes, String has no trait copy. That’s the PUZZLE.