如何确保类型安全?

bas*_*gnr 5 rust

只是浏览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分支将导致控制转移,并且其结果,即使它有一个,将永远不会被使用.


DK.*_*DK. 8

continue是,breakreturn,"发散".也就是说,编译器知道控制流不会在它之后恢复,它会转到其他地方.任何返回的函数也是如此!; 这就是编译器知道函数std::rt::begin_unwind永远不会返回的方式.

  • 注意,`!`是通常被称为*bottom*的文献,请参阅[维基百科条目](http://en.wikipedia.org/wiki/Bottom_type). (4认同)