A beginner's question about reference and iter map


#1
let s: &[u8] = "0100".as_bytes();
assert_eq!(s.iter().filter(|i| i.to_string() == b'1'.to_string()).count(), 1);// dot pierce. ok.
assert_eq!(s.iter().filter(|i| (&i).to_string() == b'1'.to_string()).count(), 1);// dot pierce. ok.
assert_eq!(s.iter().map(|&i| i - b'0').sum::<u8>(), 1);// referece pattern. ok.
assert_eq!(s.iter().map(|i| i - b'0').sum::<u8>(), 1);// why rustc allow this?
assert_eq!(s.iter().map(|i| (&i) - b'0').sum::<u8>(), 1);// but rustc don't allow this.

#2

Your code can be simplified to:

fn main() {
   let val = 1u8;
   let ref1 = &val;
   let ref2 = &&val;
   
   val - 1;
   ref1 - 1; // ok
   ref2 - 1; // err
}

So it looks like there’s a magic auto-dereferencing behavior for a single level of reference, but not double reference.

Initially, I suspected it’s related to magic auto-dereferencing of method calls, but methods work on any depth of references, so I’m surprised myself too:

use std::ops::Sub;

fn main() {
   let val = 1u8;
   let ref1 = &val;
   let ref2 = &&val;
   
   val.sub(1);
   ref1.sub(1); // ok
   ref2.sub(1); // ok, too!
}

#3

I think it’s simply because there are the required impls:

impl Sub<u8> for u8 // val - 1
impl<'a> Sub<u8> for &'a u8 // ref1 - 1

There’s no impl<'a, 'b> Sub<u8> for &'a &'b u8 (or similar).


#5

you are right.

use std::ops::Sub;
struct x8(u8);
impl<'a, 'b> Sub<u8> for &'a &'b x8 {
    type Output = u8;

    fn sub(self, rhs: u8) -> u8 {
        self.0 - rhs
    }
}

let s = x8(1);
assert_eq!((&&s) - 1, 0);