On the design of rust language and go language from the perspective of error handling

Time:2021-1-24

Golang comparison

Let’s make a comparison with go. For example, we need to convert two strings into numbers and return the results. If we use golang, the implementation is as follows:

func multiply(first_number string, second_number string) (result int, err error) {
    var (
        first  int
        second int
    )
    first, err = strconv.Atoi(first_number)
    if err != nil {
        return
    }

    second, err = strconv.Atoi(second_number)
    if err != nil {
        return
    }
    result = first * second
    return
}

As you can see, this is also the most common error handling mechanism in go language. If an error is caught, the error will be returned, otherwise the normal result will be returned. The result of dealing with errors in this way is: every error has to be dealt with by human flesh. How can there be a lot of redundant code? If there is a large amount of code, it will write a lot of redundant code, which is not elegant.

Implementation of trust

Basic version

Now, use rust to implement the same logic:

fn multiply(first_number_str: &str, second_number_str: &str) -> i32 {
    let first_number = first_number_str.parse::<i32>().unwrap();
    let second_number = second_number_str.parse::<i32>().unwrap();
    first_number * second_number
}

Compared with golang’s code, the above code doesn’t have much cash. Because when the program resolves to the program exception, it will terminate the program directly. This is very unfriendly in project development, but this is only the roughest way of implementation. We use match to optimize it

match

use std::num::ParseIntError;
type AliasResult<T> = Result<T, ParseIntError>;

#[allow(dead_code)]
fn multiply1(first_number_str: &str, second_number_str: &str) -> AliasResult<i32> {
    match first_number_str.parse::<i32>() {
        Err(e) => Err(e),
        Ok(first_number) => match second_number_str.parse::<i32>() {
            Err(e) => Err(e),
            Ok(second_number) => Ok(first_number * second_number)
        }
    }
}

This is comparable to golang in terms of implementation. If you stop here, then trust can only draw with golang. However, rust also provides a functional result processing mechanism

Using map and and_ Then implementation

#[allow(dead_code)]
fn multiply2(first_number_str: &str, second_number_str: &str) -> AliasResult<i32> {
    first_number_str.parse::<i32>().and_then(|first_number| {
        second_number_str.parse::<i32>().map(|second_number| first_number * second_number)
    })
}

As you can see, through the way of operator, rust can process the desired result through two lines of code. This is a relatively good implementation. However, compared with the previous code, but do not understand functional programming, may be relatively difficult to understand. So do we have a compromise

Realization of general compromise

#[allow(dead_code)]
fn multiply3(first_number_str: &str, second_number_str: &str) -> AliasResult<i32> {
    let first_number = match first_number_str.parse::<i32>() {
        Ok(first_number) => first_number,
        Err(e) => return Err(e)
    };

    let second_number = match second_number_str.parse::<i32>() {
        Ok(second_number) => second_number,
        Err(e) => return Err(e)
    };

    Ok(first_number * second_number)
}

The above implementation is relatively clear and easy to read, but is there a way to simplify the handling of repeated errors

#[allow(dead_code)]
fn multiply4(first_number_str: &str, second_number_str: &str) -> AliasResult<i32> {
    let first_number = first_number_str.parse::<i32>()?;
    let second_number = second_number_str.parse::<i32>()?;

    Ok(first_number * second_number)
}

However, he still does the safest error handling. At the same time, compared with golang, the amount of code is reduced by many times, and the readability of the code is also quite high. At the same time, compared with the execution efficiency of the code, trust is also superior to golang. So embrace trust~~

This work adoptsCC agreementReprint must indicate the author and the link of this article

Recommended Today

Master git thoroughly (2)

1、 Transmission Mastering git thoroughly (1)Master git thoroughly (3) 2、 Basic concepts ① Work areaThe so-called work area isThe directory you can see on your computerCan be simply understood as our project root directory is the workspace.② Version LibraryThe so-called version library is executed in the root directory of the projectgit initAfter the command, a. […]