Rust中var和_var有什么区别?

3

考虑以下情况:

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

Rust编译器会产生这个警告:

= note: #[warn(unused_variables)] on by default
= note: to avoid this warning, consider using `_variable` instead

“variable”和“_variable”有什么区别?
2个回答

10
区别在于前面有一个下划线,这会使得Rust编译器允许它未使用。它有点像裸下划线_的命名版本,可以用来忽略值。
然而,_name_的作用不同。普通下划线会立即丢弃值,而_name则像任何其他变量一样,在作用域结束时丢弃值。
以下是一个示例,说明它并不完全与普通下划线相同:
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);
    }
}

打印以下内容 (playground):

dropping count 2
dropping count 1
dropping count 3
dropping count 1
dropping count 2
dropping count 3

2
你介意更清楚地解释一下裸下划线的区别吗?这是一个相当大的区别,其中一个会立即丢弃对象,而另一个则像普通绑定一样在词法范围结束时丢弃它。 - Matthieu M.
2
另一个区别是 let _x = y; 会_移动_ y,因此该语句之后 y 不再有效,而 let _ = y; 不会移动 y - Sven Marnach

1

_variablevariable 之间的关键区别在于,第一个告诉编译器如果我们在代码中不使用它,则不要发出任何警告。例如:

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

编译 main.rs 的结果如下:
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


更有趣的情况是当我们比较__variable时。

通过将变量名以_开头来忽略未使用的变量

语法_x仍将值绑定到变量,而_根本不绑定。

考虑以下示例:

// src/main.rs
fn main() {
    let s = Some(String::from("Hello!"));

    if let Some(_s) = s {
        println!("found a string");
    }

    println!("{:?}", s);
}

当我们尝试编译main.rs时,会出现错误:

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!语法_x仍将值绑定到变量中,这意味着我们正在将s的所有权转移到_s,因此,我们无法再访问变量s;当我们尝试打印s的值时,就会发生这种情况。
上述操作的正确方式是:
// src/main.rs
fn main() {
    let s = Some(String::from("Hello!"));

    if let Some(_) = s {
        println!("found a string");
    }

    println!("{:?}", s);
}

上面的代码运行良好。s没有被移动到_中,所以我们仍然可以在后面访问它。
有时我会在迭代器中使用_
fn main() {
    let v = vec![1, 2, 3];
    let _ = v
        .iter()
        .map(|x| {
            println!("{}", x);
        })
        .collect::<Vec<_>>();
}

编译后得到结果:
1
2
3

当我在可迭代类型上进行更复杂的操作时,上面的例子对我来说就像一个实用工具。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接