我是 Rust 的新手,刚刚遇到了漂亮的if-let
结构。我有a
和b
值,它们都是Option
的。我按如下方式使用if-let
:
if let (Some(a), Some(b)) = (a, b) {
println!("You passed in {:?}, {:?}");
}
这有效,但我对为什么我需要包装我的价值观感到困惑,例如已经是Option
Some(a)
.
Option
不是已经是Some
或None
之一了吗?
这是在 rust 中使用模式匹配时的地方之一。在更简单的例子中:
let x: Option<i32> = Some(42);
if let Some(x) = x {
println!("{}", x);
}
Rust 知道x
是一个Option
类型,而这个枚举有两个可能的变体。所以这个模式匹配表达是什么看x
,再和Some(x)
比较。如果x
None
则匹配将失败(因为None
和Some(_)
是不同的变体)。但是,如果x
Some
则模式将匹配,并且Some
中的值将分配给变量x
。这将反过来隐藏以前的变量x
,并且仅在此if let
范围内有效。
您正在做的事情实际上是相同的,只是您匹配为两个选项的元组的模式。阅读《The Book》中关于模式匹配的这一章,以更好地理解它,并查看所有其他地方,你可以在 rust 中找到它。
这里要注意的是,你没有包装你的价值观。当您使用if let Some(x) = y {
时,您正在测试变量y
是否与模式Some(x)
匹配,如果是,则将x
的值绑定为选项包装的东西。你可以在这里阅读书中的模式匹配
在您的示例中,您在两侧都使用了a
和b
这一事实有点误导。您正在用新变量遮蔽原始变量。你可以写if let (Some(x), Some(y)) = (a, b) {
它本来可以工作,但a
和b
仍然是选项,x
和y
将作为先前包装的值提供。
此外,您的打印语句需要传入a
和b
。想必你的原始代码确实有它们。
您将"maybe-Some
"的内容解压缩到它所包含的值,并且只有在两者都Some
时才进入块。如果你可以写if let (a, b) = (a, b)
,它怎么知道解压缩(而不仅仅是复制)并且在None
时根本不运行?您的代码正在执行有意义的工作,既要测试Some
性,又要解压缩(和重影)原始a
,并使用它们最初持有的Some
对象的内容进行b
。如果你没有Some
,测试和拆包都不是 Rust 可以自己推断的东西。
首先,让我们暂时忘记元组,这只是这个问题的噪音。
您不需要包装它们,您可以执行以下操作:
if let a = a {
println!("{:?}", a);
}
但是if
的意义何在?在 Rust 中,这样的任务永远不会失败!
实际上,当您编写let LEFT = RIGHT;
时,LEFT
部分在技术上称为绑定,这是一种将名称(变量)绑定到值的特殊语法。
一般来说,绑定可能是错误的,如果你键入let Some(inner_a) = a;
那么如果a
是Some(42)
那么inner_a
将绑定到42
;但是如果a
是无的,, the variable
inner_a'将被取消分配,这不好。
解决这个问题的常用方法是使用匹配,尝试多个绑定,直到一个成功:
let inner_a = match a {
Some(x) => x,
None => 0,
};
if let
构造只是匹配的语法糖:
if let Some(inner_a) = a {
do_something(inner_a);
}
脱糖为:
match a {
Some(inner_a) => {
do_something(inner_a);
}
_ => {} //catch-all binding
}
TL;博士;=
左侧的Some()
不是包装值,而是解开它!