结果错误时从函数返回默认值 [英] Returning default value from function when result is error

查看:80
本文介绍了结果错误时从函数返回默认值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有类似于的东西?快捷方式,它不会在出现错误时从函数返回结果,而是返回预定义的值?

Is there something similar to the ? shortcut which instead of returning a result from a function when there is an error, returns a predefined value?

基本上我想知道是否可以在一行中执行以下操作:

Basically I want to know if it is possible to do the following in one line:

fn index() -> String {
    let temp = some_func("pass"); // some_func returns a Result 
    if temp.is_err() {
        return "No parameters named pass".to_string();
    }
    try_decrypt_data(temp.unwrap())
}

我尝试使用 unwrap_or_else(),但这只是返回闭包而不是外部函数。例如:

I tried using unwrap_or_else(), but that just returns the closure not the outer function. i.e.

try_decrypt_data(params.get("pass").unwrap_or_else(|| return "No parameters named pass".to_string(); )) // This doesn't work


推荐答案

这是可能的,但通常不是一个好主意,尤其是在您的示例中(我将在后面解释)。

This is kind of possible, but usually not a good idea, especially not in your example (I will explain that later).

您不能轻易返回 String 并生成返回默认值,但是您可以定义自己的字符串类型并实现 std :: ops :: Try 。请注意, Try 仍然不稳定!

You cannot easily return a String and make ? return a default value, but you can define your own string type and implement std::ops::Try for it. Note that Try is still unstable!

让我们看看它是如何工作的:

Let's see how this would work:

// Just wrap a string
struct StringlyResult {
    s: String,
}

// Convenience conversion 
impl From<String> for StringlyResult {
    fn from(s: String) -> Self {
        Self { s }
    }
}

// The impl that allows us to use the ? operator
impl std::ops::Try for StringlyResult {
    type Ok = String;
    type Error = String;

    fn into_result(self) -> Result<Self::Ok, Self::Error> {
        if self.s == "No parameters named pass" {
            Err(self.s)
        } else {
            Ok(self.s)
        }
    }

    fn from_error(s: Self::Error) -> Self {
        if s != "No parameters named pass" {
            panic!("wat");
        }
        Self { s }
    }

    fn from_ok(s: Self::Ok) -> Self {
        if s == "No parameters named pass" {
            panic!("wat");
        }
        Self { s } 
    }
}

这样,我们可以像这样实现 index()

With that we can implement index() like this:

fn index() -> StringlyResult {
    let temp = some_func("pass")
        .map_err(|_| "No parameters named pass")?; 
    try_decrypt_data(&temp).into()
}

(< a href = https://play.rust-lang.org/?gist=0c458e5a57c3dd204591107ada9d7cc8&version=nightly rel = nofollow noreferrer>在操场上填写代码)

是的, Try 特性使用户可以将运算符用于自己的类型。

So yes, the Try trait enables users to use the ? operator with their own types.

但是,如您的示例所示,这是一个一个可怕的想法。您可能已经注意到我上面的代码中的 wat 部分。问题在于您的OK类型已经用尽了整个类型(该类型的所有实例都是有效的OK实例)。

However, as presented in your example, this is a terrible idea. You probably already noticed the "wat" sections in my code above. The problem is that your OK-type already exhausts the whole type (all instances of the type are valid OK-instances).

考虑一个函数 get_file_size()-> u64 。现在,此功能可能会失败(即无法确定文件大小)。您不能只返回 0 来表示发生了故障。同样,您的函数调用者如何区分函数无法确定文件大小的环境和文件实际为0字节的环境?

Consider a function get_file_size() -> u64. Now this function can fail (i.e. it cannot determine the file size). You couldn't just return 0 to signal a failure occurred. How would the caller of your function distinguish between an environment in which the function cannot determine the file size and an environment where there the file is actually 0 bytes large?

函数的调用者如何区分发生错误的情况和解密的文本实际上是无参数传递的参数 的情况?来电者不能!

Similarly, how would the caller of your function distinguish the situation in which an error occurred and the situation in which the decrypted text is literally "No parameters named pass"? The caller can't! And that's bad.

注意有类似的东西,虽然还不错,但在Rust中仍然不是惯用语: get_file_size()- > i64 。在这里,我们可以返回 -1 表示失败。这还不那么糟糕,因为 -1 永远不可能是有效的文件大小! (换句话说,并非您类型的所有实例都是有效的OK实例)。但是,在这种情况下,忘记检查错误仍然非常容易。这就是为什么在Rust中,我们总是想使用 Result

Notice that there is something similar, which is not as bad, but still not really idiomatic in Rust: get_file_size() -> i64. Here, we could return -1 to signal a failure. And this is less bad because -1 can never be a valid file size! (in other words, not all instances of your type are valid OK-instances). However, in this case it is still super easy to forget to check for errors. That's why in Rust, we always want to use Result.

要使错误处理更容易,请考虑使用周转箱失败 。这样,您可以轻松地将字符串用作错误消息,而不会牺牲程序的类型安全性或完整性。示例:

To make error handling easier, consider using the crate failure. With that, you can easily use strings as error messages without sacrificing type safety or sanity of your program. Example:

use failure::{Error, ResultExt};

fn index() -> Result<String, Error> {
    let temp = some_func("pass")
        .context("No parameters named pass")?; 
    Ok(try_decrypt_data(&temp)?)
}

这篇关于结果错误时从函数返回默认值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆