【发布时间】:2021-12-01 19:23:56
【问题描述】:
我是 rust 新手,最近遇到了 trait 的问题
我有一个特征,它用作消息的来源,并作为 Box 特征对象存储在结构中。我简化了逻辑,代码看起来像这样。
#[derive(Debug)]
enum Message {
MessageTypeA(i32),
MessageTypeB(f32),
}
enum Config {
ConfigTypeA,
ConfigTypeB,
}
trait Source {
fn next(&mut self) -> Message;
}
struct SourceA;
impl Source for SourceA {
fn next(&mut self) -> Message {
Message::MessageTypeA(1)
}
}
struct SourceB;
impl Source for SourceB {
fn next(&mut self) -> Message {
Message::MessageTypeB(1.1)
}
}
struct Test {
source: Box<dyn Source>,
}
impl Test {
fn new(config: Config) -> Self {
Test {
source: match config {
Config::ConfigTypeA => Box::new(SourceA{}),
Config::ConfigTypeB => Box::new(SourceB{}),
}
}
}
fn do_sth(&mut self) -> String {
match self.source.next() {
Message::MessageTypeA(a) => format!("a is {:?}", a),
Message::MessageTypeB(b) => format!("b is {:?}", b),
}
}
fn do_sth_else(&mut self, message: Message) -> String {
match message {
Message::MessageTypeA(a) => format!("a is {:?}", a),
Message::MessageTypeB(b) => format!("b is {:?}", b),
}
}
}
不同类型的Source返回不同类型的Message,Test结构需要根据config创建对应的trait对象并在do_sth函数中调用next()。
所以你可以看到Config和Message两种枚举类型,我觉得这是一个奇怪的用法,但我不知道它有什么奇怪的地方。
我尝试使用 trait 关联类型,但是当我声明像 source: Box<dyn Source<Item=xxxx>> 这样的测试结构时需要指定关联类型,但在创建结构对象时我实际上并不知道确切的类型。
然后我尝试使用Generic类型,但是由于上层代码的需要,Test不能使用Generic。
所以请帮帮我,有没有更优雅或更质朴的解决方案来解决这种情况?
【问题讨论】:
-
这段代码编译得很好,所以我不明白是什么问题。
-
@SvetlinZarev 我想问题是让枚举的变体跟踪我们对某个特征的实现者并不是很习惯。 trait 对象的重点应该是我们不必担心到底是谁在实现它。
-
@SvetlinZarev Lagerbaer 表达了我想说的话,在这段代码中我需要模式匹配来确定
config和模式匹配来确定message,而且至关重要的是,即使我有确定trait对象是SourceA类型,我还是需要模式匹配来确定它的next()返回MessageTypeA,即使使用了if let模式,还是会有很多无用的代码。 -
对我来说,一个 trait 可以有一个返回枚举的函数是完全合理的,特别是如果“源”特征可以有不同的行为但需要遵守严格的“消息”格式。但是,如果 ConfigA 总是创建一个总是返回 MessageA 的 SourceA,对于 ConfigB 也是如此……那么混合多态样式确实很奇怪。鉴于你已经解释过你想要的,我可能会一直使用 trait 对象。
标签: rust trait-objects