Rust iterator, deref, ref from top to bottom
Publish on 2024-11-21

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.

© 2024 humbornjo :: based on 
nobloger  ::  rss