繁体   English   中英

在 rust 中实现 from_str 时,如何在 match 语句中返回错误?

[英]How do I return an error within match statement while implementing from_str in rust?

我是 rust 的新手。 我正在尝试按照示例在此处实现 from_str 特征
https://doc.rust-lang.org/std/str/trait.FromStr.html

但我不断收到指向“return Err(Self::Err)”的错误

variant or associated item not found in `black_jack_tools::PlayerDifficulty`

我知道为什么 Self::Err 没有在我的枚举中定义但我不明白为什么 rust 在这种情况下关心,因为我返回了我的 Err object 的 Err,它与 Result<Self, Self::Err> 类型。

这是我的 FromStr 下面是带有 MRE 的 rust 操场的链接

impl FromStr for PlayerDifficulty {
    type Err = ParseError;
    fn from_str(s:&str) -> Result<Self,Self::Err>{
        let result = match s {
            "Player" => Ok(PlayerDifficulty::Player),
            "Dealer" => Ok(PlayerDifficulty::Dealer),
            "Normal" => Ok(PlayerDifficulty::Normal),
            "Perfect"=> Ok(PlayerDifficulty::Perfect),
            "Micky" =>  Ok(PlayerDifficulty::Micky),
            "Elliot" => Ok(PlayerDifficulty::Elliot),
            "Cultist"=> Ok(PlayerDifficulty::Cultist),
            _ => return Err(Self::Err)
        };
    }
}

我究竟做错了什么? 有一个更好的方法吗?

您的代码存在三个问题。 第一个是如果你想在FromStr实现中引用Err类型,你需要使用<Self as FromStr>::Err

impl FromStr for PlayerDifficulty {
    type Err = ParseError;
    fn from_str(s:&str) -> Result<Self,Self::Err>{
        let result = match s {
            "Player" => Ok(PlayerDifficulty::Player),
            /* ... */
            _ => return Err(<Self as FromStr>::Err)
        };
    }
}

Self::Err尝试在PlayerDifficulty枚举中查找Err变体,但没有这样的变体。

第二个问题是std::string::ParseError实际上是std::convert::Infallible的别名,这是一个永远不会发生且无法实例化的错误。 由于您的转换可能会失败,因此您需要使用可以实例化或定义自己的错误:

struct UnknownDifficultyError;
impl FromStr for PlayerDifficulty {
    type Err = UnknownDifficultyError;
    fn from_str(s:&str) -> Result<Self,Self::Err>{
        let result = match s {
            "Player" => Ok(PlayerDifficulty::Player),
            /* ... */
            _ => return Err(UnknownDifficultyError),
        };
    }
}

最后,即使转换成功,您也需要通过删除let result =和分号来返回结果:

struct UnknownDifficultyError;
impl FromStr for PlayerDifficulty {
    type Err = UnknownDifficultyError;
    fn from_str(s:&str) -> Result<Self,Self::Err>{
        match s {
            "Player" => Ok(PlayerDifficulty::Player),
            /* ... */
            _ => return Err(UnknownDifficultyError),
        }
    }
}

操场

function 将返回最后一条语句。 去掉最后一个分号,也可以去掉内部的return语句,返回match语句的结果。

有没有更好的办法? 看起来您正在将字符串解析为enum , create enum-utils就是这样做的。 而不是用样板代码实现解析器,您只需派生它。

#[derive(Debug, PartialEq, enum_utils::FromStr)]
enum PlayerDifficulty {
    Player,
    Dealer,
    Cultist,
    Normal,
}

fn main() {
    let _x:PlayerDifficulty= "Player".parse().unwrap();
}

在你的 cargo.toml 中

[dependencies]
enum-utils = "0.1.2"

您应该定义一个自定义错误

#[derive(Debug)]
struct PlayerError;

impl std::fmt::Display for PlayerError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Could not parse player")
    }
}
impl std::error::Error for PlayerError{}

然后更改匹配总是在相同的路径中返回Result

use std::str::FromStr;

impl FromStr for PlayerDifficulty {
    type Err = PlayerError;
    fn from_str(s:&str) -> Result<Self,Self::Err>{
        match s {
            "Player" => Ok(PlayerDifficulty::Player),
            "Dealer" => Ok(PlayerDifficulty::Dealer),
            "Normal" => Ok(PlayerDifficulty::Normal),
            "Perfect"=> Ok(PlayerDifficulty::Perfect),
            "Micky" =>  Ok(PlayerDifficulty::Micky),
            "Elliot" => Ok(PlayerDifficulty::Elliot),
            "Cultist"=> Ok(PlayerDifficulty::Cultist),
            _ =>        Err(PlayerError)
        }
    }
}

并与? 传播错误。

fn main() -> (Result<(),Box<dyn std::error::Error>>) {
    let _x = PlayerDifficulty::from_str("Player")?;
    let _x = PlayerDifficulty::from_str("PlayerPlayer")?;
    Ok(())
}

暂无
暂无

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

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