我有这个枚举类型:
enum Animal {
Dog(i32),
Cat(u8),
}
现在我有一个函数将这种类型作为参数。我知道(出于某种原因)输入始终是 Cat
。我想实现这个:
fn count_legs_of_cat(animal: Animal) -> u8 {
if let Animal::Cat(c) = animal { c } else { unreachable!() }
}
我可以写得更短和/或更地道吗?
最佳答案
我看到的是为每个枚举变体引入一个新的struct
,然后在枚举上使用方法来分解它:
struct Dog(i32);
struct Cat(u8);
enum Animal {
Dog(Dog),
Cat(Cat),
}
impl Animal {
fn cat(self) -> Cat {
if let Animal::Cat(c) = self {
c
} else {
panic!("Not a cat")
}
}
fn dog(self) -> Dog {
if let Animal::Dog(d) = self {
d
} else {
panic!("Not a dog")
}
}
}
// Or better an impl on `Cat` ?
fn count_legs_of_cat(c: Cat) -> u8 {
c.0
}
您不需要结构,因为您可以只返回 u8
,但这可能很难跟踪。如果您有多个具有相同内部类型的变体,那么它可能会产生歧义。
多年来,已经有许多 RFC 对此提供语言支持(最近的一个是 RFC 2593 — Enum variant types )。该提案将允许像 Animal::Cat
这样的枚举变体也成为独立类型,因此您的方法可以直接接受 Animal::Cat
。
我几乎总是喜欢在我固有的实现中编写绝对可靠的代码并迫使调用者 panic :
impl Animal {
fn cat(self) -> Option<Cat> {
if let Animal::Cat(c) = self {
Some(c)
} else {
None
}
}
fn dog(self) -> Option<Dog> {
if let Animal::Dog(d) = self {
Some(d)
} else {
None
}
}
}
我可能会使用匹配
:
impl Animal {
fn cat(self) -> Option<Cat> {
match self {
Animal::Cat(c) => Some(c),
_ => None,
}
}
fn dog(self) -> Option<Dog> {
match self {
Animal::Dog(d) => Some(d),
_ => None,
}
}
}
从 Rust 1.34 开始,我会使用 TryFrom
除了或代替固有实现的特性:
impl TryFrom<Animal> for Cat {
type Error = Animal;
fn try_from(other: Animal) -> Result<Self, Self::Error> {
match other {
Animal::Cat(c) => Ok(c),
a => Err(a),
}
}
}
impl TryFrom<Animal> for Dog {
type Error = Animal;
fn try_from(other: Animal) -> Result<Self, Self::Error> {
match other {
Animal::Dog(d) => Ok(d),
a => Err(a),
}
}
}
考虑使用实现 std::error::Error
的专用错误类型,而不是在失败情况下直接返回 Animal
。您可能还想实现 From
以从 Cat
/Dog
返回到 Animal
。
这一切都会变得乏味,所以宏可能很有用。我敢肯定有很多好的箱子可以做到这一点,但我经常编写自己的一次性解决方案:
macro_rules! enum_thing {
(
enum $Name:ident {
$($Variant:ident($f:ident)),* $(,)?
}
) => {
enum $Name {
$($Variant($Variant),)*
}
$(
struct $Variant($f);
impl TryFrom<$Name> for $Variant {
type Error = $Name;
fn try_from(other: $Name) -> Result<Self, Self::Error> {
match other {
$Name::$Variant(v) => Ok(v),
o => Err(o),
}
}
}
)*
};
}
enum_thing! {
enum Animal {
Dog(i32),
Cat(u8),
}
}
关于enums - 当枚举变体已知时解包内部类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34953711/