Rust iterator, deref, ref from top to bottom
Publish on

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(&::Item), the input of closure is &::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.

© 2024 humbornjo :: based on 
nobloger  ::  rss