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