6

成功時 (および失敗時) に 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)?)
}

理解できない部分があります。これはコンパイルされません。expected type ()Rust のコンパイラは、「型が一致しません」と教えてくれます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 ステートメントを使用しても同じ意味を持つという印象を受けました — なぜここで違うのでしょうか?

4

2 に答える 2

8

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 ステートメントは!、別名never 型に評価されます。今は安定した錆で名前を付けることはできませんが、最終的には安定して使用できるようになります。

于 2019-11-24T04:06:01.763 に答える