[英]What is the point of diverging functions in Rust?
我已經閱讀了幾個關於 SO 的答案,並收集了這些用例:
panic!
s但我仍然不清楚為什么我們需要像這樣定義 function:
fn func() -> ! {
panic!("Error!");
}
如果它的工作方式與此相同(沒有感嘆號):
fn func() {
panic!("Error!");
}
同時,為什么我們需要使用!
在具有無限循環的函數中? 看起來這個簽名並沒有帶來任何真實的使用信息。
這些簽名之間的主要區別歸結為一個事實!
可以強制轉換為任何其他類型,因此與任何其他類型兼容(由於從未采用此代碼路徑,我們可以假設它是我們需要的任何類型)。 當我們有多個可能的代碼路徑時,這一點很重要,例如if-else
或match
。
例如,考慮以下(可能是人為的,但希望足夠清晰)代碼:
fn assert_positive(v: i32) -> u32 {
match v.try_into() {
Ok(v) => v,
Err(_) => func(),
}
}
當func
被聲明返回時!
,這個function 編譯成功。 如果我們刪除返回類型, func
將被聲明為返回()
,並且編譯中斷:
error[E0308]: `match` arms have incompatible types
--> src/main.rs:8:19
|
6 | / match v.try_into() {
7 | | Ok(v) => v,
| | - this is found to be of type `u32`
8 | | Err(_) => func(),
| | ^^^^^^ expected `u32`, found `()`
9 | | }
| |_____- `match` arms have incompatible types
您還可以將其與Result::unwrap
的定義進行比較:
pub fn unwrap(self) -> T {
match self {
Ok(t) => t,
Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e),
}
}
在這里, unwrap_failed
正在返回!
,因此它與Ok
情況下返回的任何類型相統一。
編譯器知道遵循發散表達式(w.r.t. 評估順序)的任何內容都是不可達的。 在決定是否初始化局部變量時,它可以使用此信息來避免誤報。
考慮以下示例:
use rand; // 0.8.4
fn main() {
let foo;
if rand::random::<bool>() {
foo = "Hello, world!";
} else {
diverge();
}
println!("{foo}");
}
fn diverge() {
panic!("Crash!");
}
我們聲明了一個變量foo
,但我們只在if
表達式的一個分支中初始化它。 這無法編譯並出現以下錯誤:
error[E0381]: borrow of possibly-uninitialized variable: `foo`
--> src/main.rs:10:15
|
10 | println!("{foo}");
| ^^^^^ use of possibly-uninitialized `foo`
但是,如果我們像這樣改變我們的diverge
function 的定義:
fn diverge() -> ! {
panic!("Crash!");
}
然后代碼成功編譯。 編譯器知道如果使用else
分支,它永遠不會到達println!
因為diverge()
發散。 因此, else
分支沒有初始化foo
並不是錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.