I'm writing a function that returns a serde_json::Value upon success (and failure). Previously in Rust I have been omitting the semicolon to return data from a function, like in the code example below:
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)?)
}
Here comes the part I don't understand: this doesn't compile. Rust's compiler tells me "mismatched types", and that it expected type ()
, but found type serde_json::value::Value
. Now, I found a solution to this that does compile, and it is as follows:
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)?)
}
By adding the return
statement the compiler suddenly is happy and the compiler doesn't have anything to say about it any more. Why is this? I was under the impression that omitting the semicolon and using the return statement had the same implications — why does it differ here?
They're not optional. Semicolons modify the behaviour of an expression statement so it should be a conscious decision whether you use them or not for a line of code. Almost everything in Rust is an expression. An expression is something that returns a value.
You have to use return if you want to produce a value other than the final value of the block. The official style, then, is to leave off the return in the trailing position because it's redundant.
All developers writing JavaScript should understand automatic semicolon insertion as it relates to return statements. JS uses automatic semicolon insertion. This means JS engines will execute code and insert any semicolons where it sees fit. One of those spots is after a return statement.
The return keyword can be used to return a value inside a function's body. When this keyword isn't used, the last expression is implicitly considered to be the return value. If a function returns a value, its return type is specified in the signature using -> after the parentheses () .
A return
statement, otherwise known as an early return, will return an object from the last/innermost function-like scope. (Function-like because it applies to both closures and functions)
let x = || {
return 0;
println!("This will never happen!");
};
fn foo() {
return 0;
println!("This won't happen either");
}
An absent semicolon will instead evaluate the expression, like a return
, but only return to the last/innermost scope, or in other words, it returns from within any set of {}
.
let x = { // Scope start
0
}; // Scope end
fn foo() -> usize { // Scope start
0
} // Scope end
return
statement will break out of any amount of nested scopes until it hits a function-like scope:
fn foo() -> usize {// <------------------------------------------\
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
{ // |
return 0; // ---/
}
}
}
}
}
}
}
}
}
}
}
}
The return
statement also has a type of its own, that is to say that let x = return;
will actually compile.
A return statement will evaluate to !
, AKA the never type. You can't name it in stable rust right now, but it will eventually become stable and usable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With