当前位置: 首页 > 知识库问答 >
问题:

在Rust中使用返回语句和省略分号有什么区别?

茅高卓
2023-03-14

我正在编写一个函数,它在成功(和失败)时返回一个serde\u json::值。之前在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的编译器告诉我“类型不匹配”,并且它预期的类型(),但找到了类型serde\u 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语句具有相同的含义­-为什么在这里有所不同?

共有2个答案

齐博厚
2023-03-14

正如书中所说:

在Rust中,函数的返回值与函数体块中最终表达式的值同义。

换句话说-不是表达式没有分号使其成为返回值,而是它是函数中的最终表达式。分号用于分隔表达式,因此:

fn foo() -> i32 {
    5;
}

等价于产生值5的表达式,后跟一个不产生任何结果的空表达式。因此上面的函数不会编译

如果您希望在到达最终表达式之前尽早从函数返回,则返回关键字非常有用。这就是您在示例中尝试的操作。

还要注意,所有潜在的返回值必须与函数本身的返回值具有相同的类型。

以上这些都不能完全解释您所遇到的编译器错误。您的内部匹配如下所示:

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")
}

匹配块的规则之一是,每个手臂都必须计算为相同的类型。但在上述情况下,一个arm的计算结果可能是std::result::result

插入return可以避免该错误,因为有些arm现在从函数中返回,而不是计算为std::result::result类型的值

高化
2023-03-14

返回语句,也称为早期返回,将从最后一个/最内部的类函数范围返回一个对象。(类函数,因为它适用于闭包和函数)

let x = || {
    return 0;
    println!("This will never happen!");
};
fn foo() {
    return 0;
    println!("This won't happen either");
}

缺少分号将改为计算表达式,如返回,但只返回到最后/最里面的范围,或者换句话说,它从任何一组{}中返回。

let x = {           // Scope start
    0
};                  // Scope end

fn foo() -> usize { // Scope start
    0
}                   // Scope end

return语句将跳出任意数量的嵌套作用域,直到它碰到类似作用域的函数:

fn foo() -> usize {// <------------------------------------------\
    {                                                      //    |
        {                                                  //    |
            {                                              //    |
                {                                          //    |
                    {                                      //    |
                        {                                  //    |
                            {                              //    |
                                {                          //    |
                                    {                      //    |
                                        {                  //    |
                                            {              //    |
                                                 return 0; // ---/
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

return语句也有自己的类型,也就是说,让x=return 将实际编译。

return语句的计算结果将是<代码> ,又名never类型。你现在不能把它命名为稳定锈,但它最终会变得稳定和可用。

 类似资料:
  • 问题内容: 我以为还会有另一个问题,但我找不到。在使用PHP的MySQL中,我通常用反引号封装字段名,以掩盖任何保留的名称或字符。但是,我的一位同事指出,这也可以使用方括号来实现。排除反引号与SQL Server不兼容的事实(显然),有什么区别?我应该使用哪个? 问题答案: SQL Server / T-SQL使用方括号(以及MS Access),而MySQL使用反引号。 据我所知,可以在文档中露

  • 问题内容: 如您所知,ECMAscript会尝试变得聪明,如果您未明确编写 分号 ,则会自动插入 分号 。简单的例子 仍将按预期工作。但是,如果您依靠这一点,则有一些警告。如果我们像这样重写该函数 ..那个函数现在将返回,因为解释器将在语句之后插入分号(这就是为什么始终将大括号放在与语句相同的行上的原因)。 但是,了解了所有这些之后,我现在想知道在所有浏览器和版本中,如下所示的语句的 安全性 如何

  • 问题内容: 我正在查看一些代码,并看到了以下符号。我不确定这三个点的含义以及您所说的名称。 谢谢。 问题答案: 这意味着此方法可以接收多个Object作为参数。为了更好地低估,请从此处检查以下示例: 省略号(…)标识可变数量的参数,并在以下求和方法中进行了演示。 在JVM的限制内,使用所需的任意多个用逗号分隔的整数参数来调用sumsum方法。一些示例:sum(10,20)和sum(18,20,30

  • 问题内容: 我知道什么是循环(对键进行迭代),但是第一次听说(对值进行迭代)。 我对循环感到困惑。我没有形容词。这是下面的代码: 我得到的是,遍历属性值。那么,为什么它不记录(返回)而不是?但是循环遍历每个键()。在这里,循环还会遍历键。但是不会迭代财产的价值,即。为什么会这样呢? 总而言之: 在这里,我控制台循环。它应该记录,但是在这里记录。为什么呢 问题答案: 遍历对象的可枚举属性名称。 (E

  • 问题内容: 在codeigniter手册中写道: $ this-> db-> select()接受可选的第二个参数。如果将其设置为FALSE,则CodeIgniter不会尝试使用反引号保护您的字段或表名。如果您需要复合选择语句,这将很有用。 我从CI应用程序之一中获得以下代码。 Q1。反引号`和单引号’有什么区别? Q2。我可以在上述查询中使用IF语句吗? Q3。这是什么意思? 问题答案: 在My

  • 本文向大家介绍C++ 返回值省略,包括了C++ 返回值省略的使用技巧和注意事项,需要的朋友参考一下 示例 如果从函数返回prvalue表达式,并且prvalue表达式的类型与函数的返回类型相同,则可以忽略prvalue临时对象的副本: 在这种情况下,几乎所有编译器都将忽略临时构造。