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



我是个新手。我试图在这里以实现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对象的Err,它与Result<自我,自我:错误>类型

这是我的FromStr在下面这是一个链接到带有MRE 的铁锈操场

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

游乐场

函数将返回最后一条语句。删除最后一个分号,您也可以删除内部返回语句,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();
}

在你的车里。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)
}
}
}

并将其与CCD_ 13配合使用来传播误差。

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

最新更新