首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么存在下划线前缀变量?

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

Stack Overflow用户
提问于 2018-01-20 22:02:23
回答 5查看 17.9K关注 0票数 40

我正在学习Rust,并发现在变量名称的开头添加一个下划线将使编译器不警告它是否未使用。我想知道为什么这个特性存在,因为未使用的变量是不允许的。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2018-01-20 22:27:20

我可以看到几个原因:

  • 您正在调用一个返回#[must_use]类型的函数,但在特定情况下,您知道可以安全地忽略该值。可以为此使用_模式(它不是变量绑定,而是它自己的模式,但这可能是下划线前缀约定的来源),但是您可能需要记录为什么忽略该值,或者忽略该值是什么。根据我的经验,这在测试中特别常见。
  • 函数参数:您可能必须命名一个参数,因为它是API的一部分,但实际上不需要使用它。2018年版中删除了匿名参数。
  • 宏。在宏中创建的变量以后可能会使用,也可能不会使用。如果不能在宏调用中沉默警告,那将是很烦人的。在本例中,有一个使下划线加倍的约定,这是由clippy的used_underscore_binding lint强制执行的。
  • 莱伊。您可能希望有一个变量存在,因为它的析构函数副作用,但不使用它否则。对于这个用例,不可能简单地使用_,因为_不是变量绑定,并且该值不会像变量绑定那样在封闭块的末尾被删除。
票数 40
EN

Stack Overflow用户

发布于 2018-01-21 18:36:46

下面是一些例子,说明为什么要忽略未使用的变量的行为。考虑下面的函数中的_s

代码语言:javascript
复制
fn add_numbers(f: i32, _s: i32) -> i32 {
    f + 1
}

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

下一个有用的地方是当一个类型实现了Drop,而您关心这个逻辑发生在哪里。在本例中,您可以看到需要_result变量,以便Drop在结束时发生。

代码语言:javascript
复制
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函数中使用的内容而改变。

代码语言:javascript
复制
It worked
2

代码语言:javascript
复制
2
It worked

因此,__named变量都有用途,需要根据程序的输出来选择它们。在游乐场上播放我的例子,以获得它的感觉。

票数 7
EN

Stack Overflow用户

发布于 2021-01-15 09:14:41

  • let a是一个值绑定,并且将分配一个堆栈空间来存储它的值。
  • let _a是一种类似于let a的行为。此外,它被标记为intentional,因此如果不使用_a,编译器将不会弹出警告。
  • let _是一种模式,而_是一种不能在其他地方使用的reserved identifier。这不会导致分配堆栈空间,因此=右侧的值将在此语句之后不久释放。

下面是一个示例:游乐场

代码语言:javascript
复制
pub struct Node {
    value: usize,
}

impl Drop for Node {
    fn drop(&mut self) {
        println!("drop() {}", self.value);
    }
}

pub fn square() {
    let a = Node { value: 1 };
    let _a = Node { value: 2 };
    let _ = Node { value: 3 };

    println!("Hello, world!");
}

fn main() {
    square();
}

产出如下:

代码语言:javascript
复制
drop() 3
Hello, world!
drop() 2
drop() 1

您可以阅读来了解更多信息。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48361537

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档