Referencing / dereferencing a vector element in a for loop

血红的双手。 提交于 2019-12-06 06:18:28

It can help to think of a reference as a kind of container. For comparison, consider Option, where we can "unwrap" the value using pattern-matching, for example in an if let statement:

let n = 100;
let opt = Some(n);

if let Some(p) = opt {
    // do something with p
}

We call Some and None constructors for Option, because they each produce a value of type Option. In the same way, you can think of & as a constructor for a reference. And the syntax is symmetric:

let n = 100;
let reference = &n;

if let &p = reference {
    // do something with p
}

You can use this feature in any place where you are binding a value to a variable, which happens all over the place. For example:

  1. if let, as above

  2. match expressions:

    match opt {
        Some(1) => { ... },
        Some(p) => { ... },
        None    => { ... },
    }
    match reference {
        &1 => { ... },
        &p => { ... },
    }
    
  3. In function arguments:

    fn foo(&p: &i32) { ... }
    
  4. Loops:

    for &p in iter_of_i32_refs {
        ...
    }
    

And probably more.

Note that the last two won't work for Option because they would panic if a None was found instead of a Some, but that can't happen with references because they only have one constructor, &.

does the meaning of & differ depending on context?

Hopefully, if you can interpret & as a constructor instead of an operator, then you'll see that its meaning doesn't change. It's a pretty cool feature of Rust that you can use constructors on the right hand side of an expression for creating values and on the left hand side for taking them apart (destructuring).

As apart from other languages (C++), &n in this case isn't a reference, but pattern matching, which means that this is expecting a reference.
The opposite of this would be ref n which would give you &&i32 as a type.

This is also the case for closures, e.g.

(0..).filter(|&idx| idx < 10)...

Please note, that this will move the variable, e.g. you cannot do this with types, that don't implement the Copy trait.

My confusion (and bear in mind I haven't covered patterns) is that I would expect that since n: &i32, then &n: &&i32 rather than it resolving to the value (if a double ref is even possible). Why does this happen, and does the meaning of & differ depending on context?

When you do pattern matching (for example when you write for &n in &number_list), you're not saying that n is an &i32, instead you are saying that &n (the pattern) is an &i32 (the expression) from which the compiler infers that n is an i32.

Similar things happen for all kinds of pattern, for example when pattern-matching in if let Some (x) = Some (42) { /* … */ } we are saying that Some (x) is Some (42), therefore x is 42.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!