简体   繁体   English

Rust:枚举结果的匹配语句不匹配类型错误

[英]Rust: Match statement mismatched type error for enum Result

I'm still a Rust noob and I'm writing a CLI tool that reads user input and makes API calls or local DB queries through a match statement.我仍然是 Rust 菜鸟,我正在编写一个 CLI 工具来读取用户输入并通过匹配语句进行 API 调用或本地数据库查询。 The error I'm encountering is on the line "new" => util::db::insert_number(&conn, user_input).await I'm able to make calls to functions with no return type (banner() & desc()) and return type Result outside of the match statements, but not inside.我遇到的错误是在"new" => util::db::insert_number(&conn, user_input).await我能够调用没有返回类型的函数 (banner() & desc() ) 并在匹配语句外返回类型 Result,但不在匹配语句内。 Could someone put me on the right track to resolve this issue.有人可以让我走上正确的轨道来解决这个问题。

TLDR: match statement expects return type (), but I want to call funcs with return type Result<()> TLDR:匹配语句需要返回类型 (),但我想调用返回类型为 Result<()> 的函数

ERROR:错误:

expected unit type `()` found enum `Result<(), rusqlite::Error>

cli.rs/main_loop(): cli.rs/main_loop():

pub async fn main_loop() -> Result<()> {
    banner();
    desc();
    
    let conn = Connection::open("db.db").expect("connection failed");
    util::db::check_db(&conn).await;

    let mut user_input: Vec<String>;
    let mut rl = Editor::<()>::new();
    if rl.load_history(".history").is_err() {
           println!("no previous history...");
    }
    println!("\t\t type 'new <number>' to add a number to the db");
    println!("\t\t     type 'exit' to leave configuration mode\n");
    loop {
        let readline = rl.readline("CONFIG# ");
        match readline {
            Ok(line) => {
                user_input = get_string_vec(line);
                match user_input[0].as_str() {
                    "new" => util::db::insert_number(&conn, user_input).await,
                    "exit" => break,
                    _ => continue,
                }
            },
            Err(ReadlineError::Interrupted) => {
                println!("ctrl+c pressed. quitting now..");
                std::process::exit(0);
            },
            Err(ReadlineError::Eof) => {
                println!("ctrl+d pressed. quitting now..");
                std::process::exit(0);
            },
            Err(err) => {
                println!("error: {:?}", err);
                std::process::exit(0);
            }
        }
    }
    Ok(())
}

db.rs/insert_number(): db.rs/insert_number():

pub async fn insert_number(conn: &Connection, args: Vec<String>) -> Result<()> {
    //let conn = Connection::open("db.db").expect("connection failed");
    conn.execute(
        "insert into numbers (number) values (?1)",
        &[args[1].as_str()],
    ).expect("insert failed");
    Ok(())
}

I've tried removing all cases except the case that returns Result<()>我尝试删除所有案例,但返回 Result<()> 的案例除外

Let's remove from your code everything that is noise to understand where the error comes from (ignore the fact that some variable names are now undefined):让我们从您的代码中删除所有噪音,以了解错误的来源(忽略一些变量名称现在未定义的事实):

loop {
    match readline {
        Ok(line) => {
            match user_input[0].as_str() {
                "new" => insert_number(&conn, user_input).await,
                _ => continue,
            }
        },
        _ => {}
    }
}

When Rust tried to typecheck this, among other things it will apply a rule that says that all branches of a match statement/expression should have the same type, which is the type of the match expression overall.当 Rust 尝试对此进行类型检查时,除其他事项外,它将应用一条规则,即匹配语句/表达式的所有分支应具有相同的类型,即匹配表达式的整体类型。 In particular, if you apply this rule to the outer match, you get that the inner match must has type () .特别是,如果您将此规则应用于外部匹配,您会发现内部匹配必须具有类型() Then, by applying this rule again, you get that util::db::insert_number(&conn, user_input).await must have type () .然后,通过再次应用此规则,您将得到util::db::insert_number(&conn, user_input).await必须具有类型() Thus the error.因此错误。 This is because the first branch of the outer match returns the value of the inner match.这是因为外部匹配的第一个分支返回内部匹配的值。

Thus, a very simple fix is simply因此,一个非常简单的修复就是

loop {
    match readline {
        Ok(line) => {
            match user_input[0].as_str() {
                "new" => insert_number(&conn, user_input).await,
                _ => continue,
            };
//           ^
        },
        _ => {}
    }
}

We have now enforced that the first branch of the inner match will ditch the result of the inner match, and return () by adding a semicolon.我们现在已经强制内部匹配的第一个分支将丢弃内部匹配的结果,并通过添加分号返回() Similarly, you could have wrapped the call to insert_number in drop(...) , which means "ignore this value and return () " like so:同样,您可以insert_number的调用包装在drop(...)中,这意味着“忽略此值并返回() ”,如下所示:

loop {
    match readline {
        Ok(line) => {
            match user_input[0].as_str() {
                "new" => drop(insert_number(&conn, user_input).await),
//                       ^^^^^                                      ^
                _ => continue,
            }
        },
        _ => {}
    }
}

There is one thing that I've left unsaid, however.然而,有一件事我没有说。 This code compiles , but a warning is emitted: warning: unused `Result` that must be used .此代码可以编译,但会发出警告: warning: unused `Result` that must be used The compiler is telling you that you have ditched a value of type Result , which most of the time is not what you wanted to do.编译器告诉你,你放弃了一个Result类型的值,这在大多数情况下并不是你想要做的。

This is because the type Result in Rust corresponds to error propagation.这是因为Rust中的Result类型对应的是错误传播。 Ignoring a value of type Result means possibly ignoring an error, which is probably not what you want to do.忽略Result类型的值意味着可能忽略错误,这可能不是您想要做的。 Instead, Rust assumes you want to handle that error someway.相反,Rust 假定您希望以某种方式处理该错误。

The easiest way to handle an error is simply to make the program crash if an error happens.处理错误最简单的方法就是在发生错误时让程序崩溃。 This can be done with .unwrap()这可以用.unwrap()来完成

loop {
    match readline {
        Ok(line) => {
            match user_input[0].as_str() {
                "new" => insert_number(&conn, user_input).await.unwrap(),
//                                                             ^^^^^^^^^
                _ => continue,
            }
        },
        _ => {}
    }
}

Neat, now it compiles and it doesn't give any warnings.整洁,现在它可以编译并且不会发出任何警告。 But... did you notice how that function politely gave you the possibility to handle an error, by returning a Result<(), ...> instead of just crashing if it reached an error itself.但是...您是否注意到 function 是如何礼貌地为您提供处理错误的可能性的,方法是返回Result<(), ...>而不是在它本身遇到错误时崩溃。 Most likely, the caller of the function you are writing also expects your function to be this nice as well.很可能,您正在编写的 function 的调用者也希望您的 function 也这么好。 Indeed, your function also has a return type Result<(), ...> (note that Result<()> is an alias for Result<(), T> with some predefined T ).事实上,你的 function 也有一个返回类型Result<(), ...> (注意Result<()>Result<(), T>的别名,带有一些预定义的T )。 This would be "error propagation": leave the caller handle the error, or propagate it to someone who actually wants to handle the error.这将是“错误传播”:让调用者处理错误,或将其传播给真正想要处理错误的人。 This can be done pretty easily:这可以很容易地完成:

loop {
    match readline {
        Ok(line) => {
            match user_input[0].as_str() {
                "new" => match insert_number(&conn, user_input).await {
                    Ok(()) => (),
                    Err(err) => return Err(err),
                },
                _ => continue,
            }
        },
        _ => {}
    }
}

Neat now this (probably) works.现在这(可能)很有效。 I say probably because maybe you need to transform your return Err(err) into a return Err(err.into()) , depending on the actual error types.我说可能是因为您可能需要根据实际的错误类型将您的return Err(err)转换为return Err(err.into()) It's simple and elegant, however it's also very verbose: I've added three lines just to propagate an error of a single expression.它简单而优雅,但也非常冗长:我添加了三行只是为了传播单个表达式的错误。 It would be convenient if there was some kind of short macro that did exactly this for me, right...如果有某种简短的宏可以为我做这件事会很方便,对吧......

loop {
    match readline {
        Ok(line) => {
            match user_input[0].as_str() {
                "new" => insert_number(&conn, user_input).await?,
//                                                             ^
                _ => continue,
            }
        },
        _ => {}
    }
}

Yes, ?是的, ? does exactly that.正是这样做的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM