英文:
Match enum item tuples that implement the same trait
问题
I have written a CLI program using clap
.
In it, I have several structs and enums containing these structs for the specific sub-commands.
I now ran into the issue of a certain type of code duplication and wonder, whether the Rust language has some feature, that I am unaware of, that can deduplicate this.
Here's a MRE:
pub trait Runner {
fn run(&self);
}
pub struct Foo;
impl Runner for Foo {
fn run(&self) {
println!("Fooing");
}
}
pub struct Bar;
impl Runner for Bar {
fn run(&self) {
println!("Baring");
}
}
pub enum Action {
DoFoo(Foo),
DoBar(Bar),
}
impl Runner for Action {
fn run(&self) {
match self {
Self::DoFoo(runner) => runner.run(),
Self::DoBar(runner) => runner.run(),
}
}
}
As you can see, the pattern matching on <Action as Runner>::run()
has mostly the same code on all variants, since all of the enum variant's tuples contain exactly one element that implements Runner
.
In this MRE it's quite trivial, but my actual code has currently seven variants.
Is it possible in Rust to deduplicate this pattern matching and use the fact that all variants contain a struct with the same trait?
英文:
I have written a CLI program using clap
.
In it, I have several structs and enums containing these structs for the specific sub-commands.
I now ran into the issue of a certain type of code duplication and wonder, whether the Rust language has some feature, that I am unaware of, that can deduplicate this.
Here's a MRE:
pub trait Runner {
fn run(&self);
}
pub struct Foo;
impl Runner for Foo {
fn run(&self) {
println!("Fooing");
}
}
pub struct Bar;
impl Runner for Bar {
fn run(&self) {
println!("Baring");
}
}
pub enum Action {
DoFoo(Foo),
DoBar(Bar),
}
impl Runner for Action {
fn run(&self) {
match self {
Self::DoFoo(runner) => runner.run(),
Self::DoBar(runner) => runner.run(),
}
}
}
As you can see, the pattern matching on <Action as Runner>::run()
has mostly the same code on all variants, since all of the enum variant's tuples contain exactly one element that implements Runner
.
In this MRE it's quite trivial, but my actual code has currently seven variants.
Is it possible in Rust to deduplicate this pattern matching and use the fact that all variants contain a struct with the same trait?
答案1
得分: 5
当尝试使用枚举来模仿动态分发方法(依赖于 dyn
特性)时,enum_dispatch
crate 自动化了对特性中每个方法的系统转发的样板代码。
以下是一个基于你的示例的简单示例。
在你打算为多个类型实现的特性上使用 #[enum_dispatch]
。
#[enum_dispatch(Runner)]
指示以下枚举的每个变体都是实现了该特性的类型,然后会自动生成每个变体的所有特性方法的转发(就像你手动编写的那样,每个方法都是一个 match
语句,按顺序考虑所有变体以进行调用转发)。
use enum_dispatch::enum_dispatch;
#[enum_dispatch]
pub trait Runner {
fn run(&self);
}
pub struct Foo;
impl Runner for Foo {
fn run(&self) {
println!("Fooing");
}
}
pub struct Bar;
impl Runner for Bar {
fn run(&self) {
println!("Baring");
}
}
#[enum_dispatch(Runner)]
pub enum Action {
Foo,
Bar,
}
fn main() {
let actions = [
Action::from(Foo {}),
Action::from(Bar {}),
Action::from(Bar {}),
Action::from(Foo {}),
];
for a in actions.iter() {
a.run();
}
}
/*
Fooing
Baring
Baring
Fooing
*/
英文:
When trying to mimic the dynamic-dispatch approach (relying on dyn
traits) with enums, the enum_dispatch
crate automates the boilerplate for the systematic forwarding of each method in the trait.
Here is a simple example, based on yours.
#[enum_dispatch]
is used on the trait you intend to implement for many of your types.
#[enum_dispatch(Runner)]
instructs the following enum that each of its variants are types that implement this trait, then the forwarding of every trait method is automatically generated for all of these variants, as you would do manually (each method is a match
statement considering all the variants in order to forward the call on it).
use enum_dispatch::enum_dispatch;
#[enum_dispatch]
pub trait Runner {
fn run(&self);
}
pub struct Foo;
impl Runner for Foo {
fn run(&self) {
println!("Fooing");
}
}
pub struct Bar;
impl Runner for Bar {
fn run(&self) {
println!("Baring");
}
}
#[enum_dispatch(Runner)]
pub enum Action {
Foo,
Bar,
}
fn main() {
let actions = [
Action::from(Foo {}),
Action::from(Bar {}),
Action::from(Bar {}),
Action::from(Foo {}),
];
for a in actions.iter() {
a.run();
}
}
/*
Fooing
Baring
Baring
Fooing
*/
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论