为什么存在下划线前缀变量?

时间:2018-01-20 22:02:24

标签: variables rust unused-variables

我正在学习Rust,并且发现在变量名的开头添加下划线将使编译器在未使用时不会发出警告。我想知道为什么这个功能存在,因为未使用的变量是不受欢迎的。

3 个答案:

答案 0 :(得分:11)

我可以看到几个原因:

  • 您正在调用一个返回#[must_use]类型的函数,但在您的特定情况下,您知道可以安全地忽略该值。可以使用_模式(它不是变量绑定,它是自己的模式,但这可能是下划线前缀约定来自的地方),但您可能希望记录为什么忽略该值或该值是什么。根据我的经验,这在测试中尤为常见。
  • 宏。在宏中创建的变量可能会或可能不会在以后使用。如果不能在宏调用中使警告静音,那将是令人讨厌的。在这种情况下,存在将下划线加倍的惯例,例如通过clippy的used_underscore_binding lint强制执行。
  • RAII。您可能希望为其析构函数副作用存在一个变量,否则不会使用它。对于此用例,不能简单地使用_,因为_不是变量绑定,并且该值将在语句末尾删除。

答案 1 :(得分:2)

以下是一些示例,说明为什么您可能需要忽略未使用变量的行为。请考虑以下函数中的_s

fn add_numbers(f: i32, _s: i32) -> i32 {
    f + 1
}

_s变量使得我们可以保持签名相同,即使我们没有实现它。如果我们发现我们不需要_s,但是因为我们的库在很多不同的项目中使用,我们不想将API更改为我们的函数,这也有效。这可能是也可能不是不好的做法,但在_s需要留下而不做任何事情的情况下可能会有用。我们也可以在这里使用_,但_s可能对将来变量的含义有更多的意义。

下一个有用的地方是当一个类型实现Drop时你关心那个逻辑发生的地方。在此示例中,您可以看到需要_result变量,以便最后发生Drop

fn main() {
    let mut num = 1;
    // let _ = try_add_numbers(&mut num); // Drop is called here for _
    let _result = try_add_numbers(&mut num); // without the _result we have a warning.

    println!("{}", num);
    // Drop is called here for the _result
}

// keep the api the same even if an aurgument isn't needed anymore or
// has not been used yet.
fn add_numbers(f: i32, _s: i32) -> i32 {
    f + 1
}

// This function returns a result
fn try_add_numbers(i: &mut i32) -> Result<GoodResult, GoodResult> {
    if *i > 3 {
        return Err(GoodResult(false));
    }
    *i = add_numbers(*i, 0);
    Ok(GoodResult(true))
}

struct GoodResult(bool);

impl Drop for GoodResult {
    fn drop(&mut self) {
        let &mut GoodResult(result) = self;
        if result {
            println!("It worked");
        } else {
            println!("It failed");
        }
    }
}

如果我们使用let _result = try_add_numbers(&mut num);,我们有一个在范围内的变量,直到main和drop的结尾被调用。如果我们使用let _ = try_add_numbers(&mut num);,我们仍然没有收到警告,但在语句结束时调用了drop。如果我们在没有let绑定的情况下使用try_add_numbers(&mut num);,我们会收到警告。该程序的输出确实根据我们在try_add_numbers函数中使用的内容而改变。

It worked
2

2
It worked

因此,__named变量都有用,需要根据程序输出的需要进行选择。在playground上使用我的示例来感受它。

答案 2 :(得分:-1)

我在Google偶然发现了与此匹配变量有关的警告。这是切线相关的。

有时候,您可能会在代码中获得Result并希望匹配大小写,但是您并不关心错误值。实际上,您可以只使用显式不绑定的_e而不是使用_之类的东西。这是一个具体的例子。因为我们要返回自己的错误,所以我们不在乎错误的值。

fn some_method() -> Result<u32, MyCustomError> {
    // ...
    let id: u32 = match some_str.parse() {
        Ok(value) => value,
        Err(_) => return Err(MyCustomError::Blah)
    };
    // ...
}