What's the difference between using the return statement and omitting the semicolon in Rust?

后端 未结 2 1631
借酒劲吻你
借酒劲吻你 2020-12-12 01:55

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, li

相关标签:
2条回答
  • 2020-12-12 01:59

    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.

    0 讨论(0)
  • 2020-12-12 02:04

    As it says in 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.

    In other words - it is not the fact that an expression does not have a semicolon that makes it the return value, it is the fact that it is the final expression in the function. A semicolon is used to separate expressions, so this:

    fn foo() -> i32 {
        5;
    }
    

    is equivalent to an expression yielding the value 5, followed by an empty expression that does not yield anything. Thus the function above would not compile.

    Where the return keyword comes in handy is if you want to return from a function early, before reaching the final expression. This is what you are trying to do in your example.

    Also note that all potential return values have to have the same type as the return value of the function itself.

    None of the above fully explains the compiler error you were getting though. Your inner match looks like this:

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

    One of the rules of match blocks is that each of the arms has to evaluate to the same type. But in the case above, one arm potentially evaluates to std::result::Result<serde_json::value::Value, _>, while the other does not evaluate to anything (or to be more precise, evaluates to the empty value ()).

    Inserting the return avoids that error, because the Some arm now returns from the function altogether, rather than evaluating to a value of type std::result::Result<serde_json::value::Value, _>.

    0 讨论(0)
提交回复
热议问题