将所有变体实现相同特征的枚举转换为 Rust 中的框?
Converting an enum where all variants implement the same trait to a box in Rust?
我有一个特征 Foo
,有一些实现,还有一个枚举 Foos
,每个实现有一个变体。我希望能够将我的枚举转换为 Box<dyn Foo>
.
这是我目前的解决方案:
trait Foo {}
struct FooA {}
impl Foo for FooA {}
struct FooB {}
impl Foo for FooB {}
struct FooC {}
impl Foo for FooC {}
enum Foos {
A(FooA),
B(FooB),
C(FooC),
}
impl Foos {
fn into_box(self) -> Box<dyn Foo> {
match self {
Foos::A(foo) => Box::new(foo),
Foos::B(foo) => Box::new(foo),
Foos::C(foo) => Box::new(foo),
}
}
}
它可以工作,但是 into_enum
中有很多样板。随着变体数量的增加,功能也会增加。有没有更简单的方法来做到这一点?感觉应该是one liner!
我最近想要类似的东西。我无法为您提供单行代码,但可以自动生成相应的 match
臂以及 enum
变体的宏:
macro_rules! impl_foos{($($enumvariant: ident($foo: ty),)*) => {
enum Foos {
$($enumvariant($foo),)*
}
impl Foos {
fn into_enum(self) -> Box<dyn Foo> {
match self {
$(Foos::$enumvariant(foo) => Box::new(foo),)*
}
}
}
}}
impl_foos!(
A(FooA),
B(FooB),
C(FooC),
);
这样,只有一个地方维护所有的可能性,其他的都是生成的。也许 crate enum_dispatch 也有帮助。
题外话:真的应该into_enum(self)->Box<dyn Foo>
吗?不应该是 as_foo(&self)->&dyn Foo
吗?
有了enum_dispatch
crate,你可以写
#[macro_use]
extern crate enum_dispatch;
#[enum_dispatch]
trait Foo {}
struct FooA {}
impl Foo for FooA {}
struct FooB {}
impl Foo for FooB {}
struct FooC {}
impl Foo for FooC {}
#[enum_dispatch(Foo)]
enum Foos {
A(FooA),
B(FooB),
C(FooC),
}
得到生成的impl Foo for Foos
。然后,您可以使用 Box::new
.
将 Foos
转换为 Box<dyn Foo>
这种方法有一个潜在的缺点:Box::new(Foos::A(FooA))
包含 Foos
,而不是 FooA
,因此它会产生来自 [=19 的动态调度的开销=] 到 Foos
和 enum
从 Foos
发送到 FooA
.
另一方面,现在你有了 impl Foo for Foos
: 任何你会使用 Box<dyn Foo>
的地方,你将能够直接使用 Foos
,这应该更各方面都很高效。
我有一个特征 Foo
,有一些实现,还有一个枚举 Foos
,每个实现有一个变体。我希望能够将我的枚举转换为 Box<dyn Foo>
.
这是我目前的解决方案:
trait Foo {}
struct FooA {}
impl Foo for FooA {}
struct FooB {}
impl Foo for FooB {}
struct FooC {}
impl Foo for FooC {}
enum Foos {
A(FooA),
B(FooB),
C(FooC),
}
impl Foos {
fn into_box(self) -> Box<dyn Foo> {
match self {
Foos::A(foo) => Box::new(foo),
Foos::B(foo) => Box::new(foo),
Foos::C(foo) => Box::new(foo),
}
}
}
它可以工作,但是 into_enum
中有很多样板。随着变体数量的增加,功能也会增加。有没有更简单的方法来做到这一点?感觉应该是one liner!
我最近想要类似的东西。我无法为您提供单行代码,但可以自动生成相应的 match
臂以及 enum
变体的宏:
macro_rules! impl_foos{($($enumvariant: ident($foo: ty),)*) => {
enum Foos {
$($enumvariant($foo),)*
}
impl Foos {
fn into_enum(self) -> Box<dyn Foo> {
match self {
$(Foos::$enumvariant(foo) => Box::new(foo),)*
}
}
}
}}
impl_foos!(
A(FooA),
B(FooB),
C(FooC),
);
这样,只有一个地方维护所有的可能性,其他的都是生成的。也许 crate enum_dispatch 也有帮助。
题外话:真的应该into_enum(self)->Box<dyn Foo>
吗?不应该是 as_foo(&self)->&dyn Foo
吗?
有了enum_dispatch
crate,你可以写
#[macro_use]
extern crate enum_dispatch;
#[enum_dispatch]
trait Foo {}
struct FooA {}
impl Foo for FooA {}
struct FooB {}
impl Foo for FooB {}
struct FooC {}
impl Foo for FooC {}
#[enum_dispatch(Foo)]
enum Foos {
A(FooA),
B(FooB),
C(FooC),
}
得到生成的impl Foo for Foos
。然后,您可以使用 Box::new
.
Foos
转换为 Box<dyn Foo>
这种方法有一个潜在的缺点:Box::new(Foos::A(FooA))
包含 Foos
,而不是 FooA
,因此它会产生来自 [=19 的动态调度的开销=] 到 Foos
和 enum
从 Foos
发送到 FooA
.
另一方面,现在你有了 impl Foo for Foos
: 任何你会使用 Box<dyn Foo>
的地方,你将能够直接使用 Foos
,这应该更各方面都很高效。