What is the purpose of `&` before the loop variable?

后端 未结 2 1055
悲哀的现实
悲哀的现实 2020-12-03 18:55

What is the purpose of & in the code &i in list? If I remove the &, it produces an error in largest = i, sinc

2条回答
  •  攒了一身酷
    2020-12-03 19:33

    This is the effect of destructuring. I won't completely describe that feature here, but in short:

    In many syntax contexts (let bindings, for loops, function arguments, ...) , Rust expects a "pattern". This pattern can be a simple variable name, but it can also contain some "destructuring elements", like &. Rust will then bind a value to this pattern. A simple example would be something like this:

    let (a, b) = ('x', true);
    

    On the right hand side there is a value of type (char, bool) (a tuple). This value is bound to the left hand pattern ((a, b)). As there is already a "structure" defined in the pattern (specifically, the tuple), that structure is removed and a und b bind to the tuple's elements. Thus, the type of a is char and the type of b is bool.

    This works with a couple of structures, including arrays:

    let [x] = [true];
    

    Again, on the right side we have a value of type [bool; 1] (an array) and on the left side we have a pattern in the form of an array. The single array element is bound to x, meaning that the type of x is bool and not [bool; 1]!

    And unsurprisingly, this also works for references!

    let foo = 0u32;
    let r = &foo;
    let &c = &foo;
    

    Here, foo has the type u32 and consequently, the expression &foo has the type &u32. The type of r is also &u32, as it is a simple let binding. The type of c is u32 however! That is because the "reference was destructured/removed" by the pattern.

    A common misunderstanding is that syntax in patterns has exactly the opposite effect of what the same syntax would have in expressions! If you have a variable a of type [T; 1], then the expression [a] has the type [[T; 1]; 1] → it adds stuff. However, if you bind a to the pattern [c], then ´yhas the typeT` → it removes stuff.

    let a = [true];    // type of `a`: `[bool; 1]`
    let b = [a];       // type of `b`: `[[bool; 1]; 1]`
    let [c] = a;       // type of `c`: `bool`
    

    This also explains your question:

    It seems like it is somehow dereferencing, but then why in the below code, it is not working?

    fn main() {
       let mut hey:i32 = 32;
       let x:i32 = 2;
       hey = &&x;
    }
    

    Because you use & on the expression side, where it adds a layer of references.


    So finally about your loop: when iterating over a slice (as you do here), the iterator yields reference to the slice's elements. So in the case for i in list {}, i has the type &i32. But the assignment largest = i; requires a i32 on the right hand side. You can achieve this in two ways: either dereference i via the dereference operator * (i.e. largest = *i;) or destructure the reference in the loop pattern (i.e. for &i in list {}).


    Related questions:

    • Iterating over a slice's values instead of references in Rust?
    • Why is & needed to destructure a list of tuples during iteration?

提交回复
热议问题