What's the semantic of assignment in Rust?

后端 未结 1 605
夕颜
夕颜 2020-12-04 00:47

How could know the type of a binding if I use auto type deduction when creating a binding? what if the expression on the right side is a borrow(like let x = &5;

相关标签:
1条回答
  • 2020-12-04 01:25

    I sense some confusion between binding and assigning:

    • Binding introduces a new variable, and associates it to a value,
    • Assigning overwrites a value with another.

    This can be illustrated in two simple lines:

    let mut x = 5;    //  Binding
    x = 10;           //  Assigning
    

    A binding may appear in multiple places in Rust:

    • let statements,
    • if let/while let conditions,
    • cases in a match expression,
    • and even in a for expression, on the left side of in.

    Whenever there is a binding, Rust's grammar also allows pattern matching:

    • in the case of let statements and for expressions, the patterns must be irrefutable,
    • in the case of if let, while let and match cases, the patterns may fail to match.

    Pattern matching means that the type of the variable introduced by the binding differs based on how the binding is made:

    let x = &5;    //  x: &i32
    let &y = &5;   //  y: i32
    

    Assigning always requires using =, the assignment operator.

    When assigning, the former value is overwritten, and drop is called on it if it implements Drop.

    let mut x = 5;
    x = 6;
    //  Now x == 6, drop was not called because it's a i32.
    
    let mut s = String::from("Hello, World!");
    s = String::from("Hello, 神秘德里克!");
    //  Now s == "Hello, 神秘德里克!", drop was called because it's a String.
    

    The value that is overwritten may be as simple as an integer or float, a more involved struct or enum, or a reference.

    let mut r = &5;
    r = &6;
    //  Now r points to 6, drop was not called as it's a reference.
    

    Overwriting a reference does not overwrite the value pointed to by the reference, but the reference itself. The original value still lives on, and will be dropped when it's ready.

    To overwrite the pointed to value, one needs to use *, the dereference operator:

    let mut x = 5;
    let r = &mut x;
    *r = 6;
    //  r still points to x, and now x = 6.
    

    If the type of the dereferenced value requires it, drop will be called:

    let mut s = String::from("Hello, World!");
    let r = &mut s;
    *r = String::from("Hello, 神秘德里克!");
    //  r still points to s, and now s = "Hello, 神秘德里克!".
    

    I invite you to use to playground to and toy around, you can start from here:

    fn main() {
        let mut s = String::from("Hello, World!");
        {
            let r = &mut s;
            *r = String::from("Hello, 神秘德里克!");
        }
        println!("{}", s);
    }
    

    Hopefully, things should be a little clearer now, so let's check your samples.

    let x = &5;
    

    x is a reference to i32 (&i32). What happens is that the compiler will introduce a temporary in which 5 is stored, and then borrow this temporary.

    let mut x: &mut T = T{};
    

    Is impossible. The type of T{} is T not &mut T, so this fails to compile. You could change it to let mut x: &mut T = &mut T{};.

    And your last example is similar.

    0 讨论(0)
提交回复
热议问题