What's the difference between var and _var in Rust?

后端 未结 2 758
一整个雨季
一整个雨季 2021-01-21 18:05

Given this:

fn main() {
   let variable = [0; 15];
}

The Rust compiler produces this warning:



        
相关标签:
2条回答
  • 2021-01-21 18:31

    The key difference between _variable and variable is that first one tells compiler not to give any warnings if we do not use it in our code. Example:

    // src/main.rs
    fn main() {
        let _x = 1;
        let y = 2;
    }
    

    Compiling main.rs gives:

    warning: unused variable: `y`
     --> src/main.rs:3:9
      |
    3 |     let y = 2;
      |         ^ help: if this is intentional, prefix it with an underscore: `_y`
      |
      = note: `#[warn(unused_variables)]` on by default
    
    

    The more interesting case is when we are comparing _ with _variable.

    Ignoring an Unused Variable by Starting Its Name with _:

    The syntax _x still binds the value to the variable, whereas _ doesn’t bind at all.

    Consider example:

    // src/main.rs
    fn main() {
        let s = Some(String::from("Hello!"));
    
        if let Some(_s) = s {
            println!("found a string");
        }
    
        println!("{:?}", s);
    }
    

    When we try to compile main.rs we get error:

    error[E0382]: borrow of moved value: `s`
     --> src/main.rs:8:22
      |
    4 |     if let Some(_s) = s {
      |                 -- value moved here
    ...
    8 |     println!("{:?}", s);
      |                      ^ value borrowed here after partial move
      |
      = note: move occurs because value has type `std::string::String`, which does not implement the `Copy` trait
    help: borrow this field in the pattern to avoid moving `s.0`
      |
    4 |     if let Some(ref _s) = s {
      |                 ^^^
    

    Aha! The syntax _x still binds the value to the variable, which means that we are moving the ownership of s to _s, thus, we can no longer access variable s anymore; which happens when we try to print value of s.

    The correct way of doing the above is:

    // src/main.rs
    fn main() {
        let s = Some(String::from("Hello!"));
    
        if let Some(_) = s {
            println!("found a string");
        }
    
        println!("{:?}", s);
    }
    

    Above code works just fine. s does not get moved into _, so we can still access it later.

    Sometimes I use _ with iterators:

    fn main() {
        let v = vec![1, 2, 3];
        let _ = v
            .iter()
            .map(|x| {
                println!("{}", x);
            })
            .collect::<Vec<_>>();
    }
    

    Compiling gives result:

    1
    2
    3
    

    When doing more complex operations on iterable types above example acts as utility for me.

    0 讨论(0)
  • 2021-01-21 18:34

    The difference is an underscore at the front, which causes the Rust compiler to allow it to be unused. It is kind of a named version of the bare underscore _ which can be used to ignore a value.

    However, _name acts differently than _. The plain underscore drops the value immediately while _name acts like any other variable and drops the value at the end of the scope.

    An example of how it does not act exactly the same as a plain underscore:

    struct Count(i32);
    
    impl Drop for Count {
        fn drop(&mut self) {
            println!("dropping count {}", self.0);
        }
    }
    
    fn main() {
        {
            let _a = Count(3);
            let _ = Count(2);
            let _c = Count(1);
        }
    
        {
            let _a = Count(3);
            let _b = Count(2);
            let _c = Count(1);
        }
    }
    

    prints the following (playground):

    dropping count 2
    dropping count 1
    dropping count 3
    dropping count 1
    dropping count 2
    dropping count 3
    
    0 讨论(0)
提交回复
热议问题