簡體   English   中英

在 Rust 中使用 return 語句和省略分號有什么區別?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM