[英]What's the difference between using the return statement and omitting the semicolon in Rust?
我正在編寫一個函數,該函數在成功(和失敗)時返回 serde_json::Value。 以前在 Rust 中,我一直省略分號以從函數返回數據,如下面的代碼示例所示:
use serde_json::{Result, Value};
use core::result::Result as ResultCore;
fn returning_function() -> ResultCore<Value, Value> {
let data = r#"
{
"status": "ok",
"response": {
"data": "secret message!"
}
}
"#;
match str_to_json(data) {
Ok(json_data) => match json_data["status"].as_str() {
Some(status_str) => {
if status_str == "ok" {
Ok(json_data["response"].clone())
}
}
None => eprintln!("\"status\" was not a string")
}
Err(error) => eprintln!("something went wrong! here's what: {}", error)
}
Err(serde_json::Value::Null)
}
fn str_to_json(json_data: &str) -> Result<Value> {
Ok(serde_json::from_str(json_data)?)
}
這是我不明白的部分:這不能編譯。 Rust 的編譯器告訴我“類型不匹配”,它expected type ()
,但found type serde_json::value::Value
。 現在,我找到了一個可以編譯的解決方案,如下所示:
use serde_json::{Result, Value};
use core::result::Result as ResultCore;
fn returning_function() -> ResultCore<Value, Value> {
let data = r#"
{
"status": "ok",
"response": {
"data": "secret message!"
}
}
"#;
match str_to_json(data) {
Ok(json_data) => match json_data["status"].as_str() {
Some(status_str) => {
if status_str == "ok" {
return Ok(json_data["response"].clone());
// ^ added return statement here
}
}
None => eprintln!("\"status\" was not a string")
}
Err(error) => eprintln!("something went wrong! here's what: {}", error)
}
Err(serde_json::Value::Null)
}
fn str_to_json(json_data: &str) -> Result<Value> {
Ok(serde_json::from_str(json_data)?)
}
通過添加return
語句,編譯器突然很高興,編譯器不再有什么可說的了。 為什么是這樣? 我的印象是省略分號和使用 return 語句具有相同的含義——為什么這里不同?
return
語句,也稱為提前返回,將從最后/最內部的類似函數的作用域中返回一個對象。 (類函數,因為它適用於閉包和函數)
let x = || {
return 0;
println!("This will never happen!");
};
fn foo() {
return 0;
println!("This won't happen either");
}
不存在的分號將改為評估表達式,就像return
,但只返回到最后/最里面的范圍,或者換句話說,它從{}
任何集合中返回。
let x = { // Scope start
0
}; // Scope end
fn foo() -> usize { // Scope start
0
} // Scope end
return
語句會跳出任意數量的嵌套作用域,直到它遇到一個類似函數的作用域:
fn foo() -> usize {// <------------------------------------------\
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
return 0; // ---/
}
}
}
}
}
}
}
}
}
}
}
}
return
語句也有自己的類型,即let x = return;
實際上會編譯。
return 語句將評估為!
,又名永不鍵入。 你現在不能用穩定銹命名它,但它最終會變得穩定和可用。
正如 書中所說:
在 Rust 中,函數的返回值與函數體塊中最終表達式的值是同義詞。
換句話說 - 表達式沒有分號使其成為返回值並不是事實,而是它是函數中的最終表達式。 分號用於分隔表達式,因此:
fn foo() -> i32 {
5;
}
相當於一個產生值 5 的表達式,后跟一個不產生任何東西的空表達式。 因此上面的函數將無法編譯。
return
關鍵字派上用場的地方是,如果您想在到達最終表達式之前盡早從函數返回。 這就是您在示例中嘗試執行的操作。
另請注意,所有潛在的返回值必須與函數本身的返回值具有相同的類型。
以上都沒有完全解釋您遇到的編譯器錯誤。 您的內部匹配如下所示:
match json_data["status"].as_str() {
Some(status_str) => {
if status_str == "ok" {
Ok(json_data["response"].clone())
}
}
None => eprintln!("\"status\" was not a string")
}
匹配塊的規則之一是每個臂都必須評估為相同的類型。 但在上述情況下,一個手臂可能評估為std::result::Result<serde_json::value::Value, _>
,而另一個不評估任何內容(或者更准確地說,評估為空值()
)。
插入return
避免了該錯誤,因為Some
arm 現在完全從函數返回,而不是評估為std::result::Result<serde_json::value::Value, _>
類型的std::result::Result<serde_json::value::Value, _>
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.