rust 有没有一种方法可以在枚举变量上调用trait方法,该变量具有实现trait的字段?

aamkag61  于 2023-01-02  发布在  其他
关注(0)|答案(2)|浏览(159)

我的枚举有40ish个变体,其中大约一半实现了trait,但这里有一个更简单的例子:

trait CheeseBoard {
    fn say_cheese(self);
}

struct Cheese {
    name: String,
}

impl CheeseBoard for Cheese {
    fn say_cheese(self) {
        println!("I am {}", self.name);
    }
}

struct Person {
    name: String,
}

impl CheeseBoard for Person {
    fn say_cheese(self) {
        println!("{} says cheese!", self.name);
    }
}

enum CheesyPerson {
    Cheese(Cheese),
    Person(Person),
    UncheesyNonperson,
}

fn main() {
    let _a = [
        CheesyPerson::Cheese(Cheese {
            name: "Gouda".into(),
        }),
        CheesyPerson::Person(Person {
            name: "Peer".into(),
        }),
        CheesyPerson::UncheesyNonperson,
    ];
    todo!("Call say_cheese on items in _a where the enum variant has exactly one field that implements the CheeseBoard trait.")
}
mrwjdhj3

mrwjdhj31#

这在Rust中是不可能的;它甚至没有匹配"具有单个值任何枚举可能性"的机制,更不用说实现特定特征了。
我能想到的最简洁的实现方法是使用一个helper方法返回一个Option<&dyn CheeseBoard>

impl CheesyPerson {
    fn get_cheese_board(&self) -> Option<&dyn CheeseBoard> {
        match self {
            Self::Cheese(v) => Some(v),
            Self::Person(v) => Some(v),
            _ => None,
        }
    }
}

现在您可以执行以下操作:

for v in _a.iter().filter_map(|v| v.get_cheese_board()) {
    v.say_cheese();
}

注意,这需要修改CheeseBoard::say_cheese方法,因为现在它通过值获取self,在此过程中消耗CheeseBoard

trait CheeseBoard {
    fn say_cheese(&self);
    //            ^
    // Add this to take self by reference
}

Playground

j9per5c4

j9per5c42#

谢谢@cdhowie,你的评论让我免于又一个小时的折磨!
如果有人用另一层结构 Package 枚举,请确保您 * 借用 * 枚举,而不是复制它。

struct RoomForOne(CheesyPerson);

impl RoomForOne {
    fn get_cheese_board(&self) -> Option<&dyn CheeseBoard> {
        match &self.0 { // & here is important!
            CheesyPerson::Cheese(v) => Some(v),
            CheesyPerson::Person(v) => Some(v),
            _ => None,
        }
    }
}

相关问题