我正在编写一个函数,在成功(和失败)时返回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语句有相同的含义?-为什么这里有不同?
3条答案
按热度按时间3phpmpom1#
一个
return
语句,也称为早期返回,将从最后/最里面的类函数作用域返回一个对象。(类函数是因为它同时适用于闭包和函数)一个不存在的分号将代替计算表达式,就像一个
return
,但只返回到最后/最里面的作用域,或者换句话说,它从任何{}
集合中返回。return
语句将打破任何数量的嵌套作用域,直到它遇到类似函数的作用域:return
语句也有自己的类型,也就是说let x = return;
实际上会编译。return语句的计算结果为
!
,也就是the never type。现在还不能在stable rust中命名它,但它最终会变得稳定和可用。5rgfhyps2#
正如The Book中所说:
在Rust中,函数的返回值与函数体块中最终表达式的值同义。
换句话说,并不是一个表达式没有分号,所以它是返回值,而是它是函数中的最后一个表达式。分号用于分隔表达式,所以这:
等价于一个产生值5的表达式,后面跟着一个不产生任何值的空表达式。因此上面的函数将无法编译。
return
关键字的用处是如果你想在到达最终表达式之前从函数中提前返回。这就是你在例子中试图做的。还要注意,所有可能的返回值必须与函数本身的返回值具有相同的类型。
以上都没有完全解释你得到的编译器错误。你的内部匹配看起来像这样:
匹配块的规则之一是每个分支都必须计算为相同的类型。但是在上面的例子中,一个分支可能计算为
std::result::Result<serde_json::value::Value, _>
,而另一个不计算任何值(或者更准确地说,计算为空值()
)。插入
return
避免了这个错误,因为Some
臂现在完全从函数返回,而不是计算为std::result::Result<serde_json::value::Value, _>
类型的值。dl5txlt93#
上面的错误实际上是由if表达式的隐式return()而没有else引起的。