在 Rust 中使用 return 语句和省略分号有什么区别?
What's the difference between using the return statement and omitting the semicolon in Rust?
我正在编写一个函数,在成功(和失败)时 return 是 serde_json::Value。以前在 Rust 中,我一直在省略函数中 return 数据的分号,如下面的代码示例所示:
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 的编译器告诉我 "mismatched types",它 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 语句具有相同的含义 - 为什么这里不同?
A return
语句,也称为早期的 return,将 return 来自 last/innermost 类似函数范围的对象。 (类似于函数,因为它适用于闭包和函数)
let x = || {
return 0;
println!("This will never happen!");
};
fn foo() {
return 0;
println!("This won't happen either");
}
缺少分号将改为计算表达式,如 return
,但仅 return 到 last/innermost 范围,换句话说,它 returns来自任何一组 {}
.
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;
会实际编译。
A return 语句将计算为 !
,又名 the never type。你现在不能用 stable rust 命名它,但它最终会变得稳定和可用。
正如The Book中所说:
In Rust, the return value of the function is synonymous with the value of the final expression in the block of the body of a function.
换句话说,并不是表达式没有分号使其成为 return 值,而是它是函数中的最终表达式。分号用于分隔表达式,因此:
fn foo() -> i32 {
5;
}
等同于一个产生值 5 的表达式,后跟一个不产生任何结果的空表达式。因此上面的函数将无法编译。
return
关键字派上用场的地方是,如果您想 return 在到达最终表达式之前尽早从函数中退出。这就是您在示例中尝试做的事情。
另请注意,所有潜在的 return 值必须与函数本身的 return 值具有相同的类型。
上面的 None 充分解释了您遇到的编译器错误。你的内心匹配看起来像这样:
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
分支现在完全来自函数 return,而不是评估类型 std::result::Result<serde_json::value::Value, _>
的值。
我正在编写一个函数,在成功(和失败)时 return 是 serde_json::Value。以前在 Rust 中,我一直在省略函数中 return 数据的分号,如下面的代码示例所示:
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 的编译器告诉我 "mismatched types",它 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 语句具有相同的含义 - 为什么这里不同?
A return
语句,也称为早期的 return,将 return 来自 last/innermost 类似函数范围的对象。 (类似于函数,因为它适用于闭包和函数)
let x = || {
return 0;
println!("This will never happen!");
};
fn foo() {
return 0;
println!("This won't happen either");
}
缺少分号将改为计算表达式,如 return
,但仅 return 到 last/innermost 范围,换句话说,它 returns来自任何一组 {}
.
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;
会实际编译。
A return 语句将计算为 !
,又名 the never type。你现在不能用 stable rust 命名它,但它最终会变得稳定和可用。
正如The Book中所说:
In Rust, the return value of the function is synonymous with the value of the final expression in the block of the body of a function.
换句话说,并不是表达式没有分号使其成为 return 值,而是它是函数中的最终表达式。分号用于分隔表达式,因此:
fn foo() -> i32 {
5;
}
等同于一个产生值 5 的表达式,后跟一个不产生任何结果的空表达式。因此上面的函数将无法编译。
return
关键字派上用场的地方是,如果您想 return 在到达最终表达式之前尽早从函数中退出。这就是您在示例中尝试做的事情。
另请注意,所有潜在的 return 值必须与函数本身的 return 值具有相同的类型。
上面的None 充分解释了您遇到的编译器错误。你的内心匹配看起来像这样:
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
分支现在完全来自函数 return,而不是评估类型 std::result::Result<serde_json::value::Value, _>
的值。