只是浏览the Rust guide(猜谜游戏),这段代码对我来说似乎不对:
let num = match input_num {
Some(num) => num,
None => {
println!("Please input a number!");
continue;
}
};
num
的类型推断在这种情况下如何工作?第一个匹配案例显然返回一个数字,而第二个匹配案例只是println
& continue
语句,它不会返回任何内容(或返回()
)。编译器如何假设它的类型安全?
答案 0 :(得分:15)
让我们更仔细地看一下这段代码:
loop {
// ... some code omitted ...
let num = match input_num {
Some(num) => num,
None => {
println!("Please input a number!");
continue;
}
};
// ... some code omitted ...
}
match语句位于循环内,语言中有几个构造可以帮助控制循环过程。 break
提前退出循环,而continue
跳过循环中的其余代码并返回其开头(重新启动它)。所以上面这个匹配基本上可以理解为“检查数字,如果它在那里,将其分配给num
变量,否则输出一条消息并从头开始重启”。
“否则”分支的行为很重要:它以控制转移操作结束,在这种情况下为continue
。编译器看到continue
并知道循环将重新启动。因此,这个分支产生的价值并不重要,因为它永远不会被使用!它也许永远不会产生任何结果。
这种行为通常用所谓的bottom type建模,它是任何类型的子类型,根本没有值。 Rust没有子类型(基本上),所以这种类型非常神奇。它在类型签名中表示为!
:
fn always_panic() -> ! {
panic!("oops!")
}
这个函数总是会引起恐慌,导致堆栈展开并最终终止它所调用的线程,所以它的返回值(如果有的话)永远不会被读取或以其他方式检查,所以绝对不能返回任何东西即使它在表达式上下文中使用,它需要一些具体的类型:
let value: int = always_panic();
因为always_panic()
具有返回类型!
,编译器知道它不会返回任何内容(在这种情况下因为always_panic()
启动堆栈展开),允许它是安全的用于代替任何类型 - 毕竟,即使它在那里,价值永远不会被使用。
continue
完全以相同的方式工作,但在本地。 None
分支“返回”类型!
,但Some
分支返回某个具体数字类型的值,因此整个匹配语句属于此数字类型,因为编译器知道{{1分支将导致控制转移,其结果,即使它有一个,也永远不会被使用。
答案 1 :(得分:8)
continue
以及break
和return
,"发散"。也就是说,编译器知道控制流不会在它之后恢复,它会转到其他地方。对于返回!
的任何函数也是如此;这就是编译器知道像std::rt::begin_unwind
这样的函数永远不会返回的原因。