当enum变量已知时展开内部类型

时间:2016-01-22 18:38:35

标签: enums rust

我有这个枚举类型:

enum Animal {
    Dog(i32),
    Cat(u8),
}

现在我有一个将此类型作为参数的函数。我知道(由于某种原因)输入始终是Cat。我想实现这个目标:

fn count_legs_of_cat(animal: Animal) -> u8 {
    if let Animal::Cat(c) = animal { c } else { unreachable!() }
}

我可以写这个更短和/或更习惯吗?

3 个答案:

答案 0 :(得分:13)

不是真的。我所看到的是为每个枚举变体引入一个新的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,但这可能很难跟踪。

然而,未来会有更好的支持。我认为它是"efficient code reuse" RFC,但在博文Virtual Structs Part 3: Bringing Enums and Structs Together中有更好的描述。该提案将允许Animal::Cat成为独立类型,因此您的方法可以接受Animal::Cat,而不必担心它。

就个人而言,我几乎总是喜欢在我固有的实现中编写可靠的代码并强迫调用者恐慌:

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

我可能会使用match

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

答案 1 :(得分:2)

试试 enum-as-inner crate,它和 Shepmaster 的回答完全一样。

答案 2 :(得分:0)

我写了一个小宏来提取已知的枚举变量:

#[macro_export]
macro_rules! extract_enum_value {
  ($value:expr, $pattern:pat => $extracted_value:expr) => {
    match $value {
      $pattern => $extracted_value,
      _ => panic!("Pattern doesn't match!"),
    }
  };
}

let cat = extract_enum_value!(animal, Animal::Cat(c) => c);

但是,我不确定这是否符合您的需要。