Rust语言: "if let Some(x) = x" 是做什么的?

22

我正在处理一个写于几年前的 Rust 项目,遇到了下面这段文字:

let mut values = vec![];
for x in maybe_values {
    if let Some(x) = x {
        values.push(Arc::new(x));
    }
}

我理解"if let"引入了一种模式匹配 if 的方式(似乎是对关键字"let"的糟糕重用,但我会克服这个问题——如果有人能帮我想出一个能让"let"在此处有意义的记忆技巧,请务必告诉我!)。

但是,测试Some(x) = x是做什么的呢?

根据我的测试,它似乎是一种技巧或惯用法,既可以a)测试循环变量'x'是否为Some(),也可以b)最终以unwrap()的值结束在x中。

但我不能完全向自己解释它,也找不到任何地方提到这是一种惯用法。

希望你能帮助我学习Rust。谢谢。


3
如何“读取”if let表达式? 为什么if-let中有let关键字? - Chayim Friedman
2
Some(x) 中的 x 是一个全新的变量,因此我认为使用 let 是必要的。如果有什么问题,在匹配语句中模式匹配时缺少 letmatch opt { Some(x) => {}, None => {} } 会创建一个没有 let 的变量 x,如果 x 也是作用域内的 const 的名称,则可能会令人困惑。 - BallpointBen
1
@BallpointBen 其实,逻辑上应该是 if Some(let x) = ...,在 let 语句和参数声明中也是一样的。我知道有些人后悔没有在模式中使用变量匹配修饰符(例如 let)。 - Chayim Friedman
4个回答

21

当您只关心匹配单个用例时,这是使用完整匹配语句的速记符号。

因此,以下代码块:

if let x = y {
   foo();
} else {
   bar();
}

等同于使用完全匹配:

match y {
    x => {
        foo();
    }
    _ => {
        bar();
    }
}

对于您的特定情况,它相当于这个样子。内部x使用与外部变量相同的名称,这可能会令人困惑,但它们是两个单独的值。

let mut values = vec![];
for x in maybe_values {
    match x {
        Some(y) => values.push(Arc::new(y)),
        _ => {},
    }
}

2
如果我可以授予两个绿色的勾,我会这么做;-) 我从来没有想过"if let"在左侧创建新的内部变量。这有助于使"let"的使用更清晰!说实话,当我开始阅读Rust代码时,"if let"语句对我来说是一些最奇怪的...谢谢。就个人而言,我会尽量避免使用相同的变量名-"没有巧妙代码的团队奖励!"恰恰相反... - spechter

14
这里涉及到两个完全不同的变量。这相当于。
let mut values = vec![];
for x_1 in maybe_values {
  if let Some(x_2) = x_1 {
    values.push(Arc::new(x_2));
  }
}

在Rust中,let语句的右侧会先于左侧变量不在作用域内进行求值,因此当执行if let语句时,外部的x仍然在作用域内。然后,如果它是一个Some值,我们就创建一个新的变量x,其中包含Option内部的值。这个变量会遮蔽前面的x,使得在if语句中无法访问之前的x(就像函数参数命名为x会遮蔽全局变量x一样)。

谢谢!不确定哪个先回答了,但会把胜利奖给你,因为你提供了核心答案 - 它们是两个分开的变量,但都被称为x! - spechter

2
我的两分钱:理解/记住if-let的另一个好助记符是将其视为一种非常常见的模式的快捷方式:if a.is_some() { let b = a.unwrap() ... }

完整模式:

let mut values = vec![];
for x_1 in maybe_values {
    if x_1.is_some() {
       let x_2 = x_1.unwrap()
       values.push(Arc::new(x_2));
    }
}

if-let 这个快捷方式将 if x_1.is_some()let x_2 = x.unwrap() 结合成一个单独的 if-let 语句。

使用这个快捷方式:

let mut values = vec![];
for x_1 in maybe_values {
    if let Some(x_2) = x_1 {
       values.push(Arc::new(x_2));
    }
}

0
基本上,maybe_values 中充满了 Options。有些是 None,而有些值是 Some(x)
如果 maybe_value 不是 None(意味着它能匹配 Some(x)),它将被追加到 values 向量中。
这个 for 循环实际上是将 maybe_values 向量中的 None/NULL 值清除,转换为一个向量(for_sure_are_values),其中所有的值都是存在的。

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