Rust 使用枚举对结构进行分组

Rust 使用枚举对结构进行分组,rust,Rust,在Rust中,应该如何对相关结构进行分组,以便函数签名可以在引用方法体中的具体类型时接受多个不同类型 为了简单起见,设计了以下示例: enum Command { Increment {quantity: u32}, Decrement {quantity: u32}, } fn process_command(command: Command) { match command { Command::Increment => increase(co

在Rust中,应该如何对相关结构进行分组,以便函数签名可以在引用方法体中的具体类型时接受多个不同类型

为了简单起见,设计了以下示例:

enum Command {
    Increment {quantity: u32},
    Decrement {quantity: u32},
}

fn process_command(command: Command) {
    match command {
        Command::Increment => increase(command),
        Command::Decrement => decrease(command),
    };
}

fn increase(increment: Command::Increment) {
    println!("Increasing by: {}.", increment.quantity);
}

fn decrease(decrement: Command::Decrement) {
    println!("Decreasing by: {}.", decrement.quantity);
}

fn main() {
    let input = "Add";
    let quantity = 4;

    let command: Command = match input {
        "Add" => Command::Increment { quantity: quantity },
        "Subtract" => Command::Decrement { quantity: quantity },
        _ => unreachable!(),
    };

    process_command(command);
}
编译会导致以下两个错误:

src/main.rs:13:24: 13:42 error: found value name used as a type: DefVariant(DefId { krate: 0, node: 4 }, DefId { krate: 0, node: 5 }, true) [E0248]
src/main.rs:13 fn increase(increment: Command::Increment) {
                                      ^~~~~~~~~~~~~~~~~~
src/main.rs:17:24: 17:42 error: found value name used as a type: DefVariant(DefId { krate: 0, node: 4 }, DefId { krate: 0, node: 8 }, true) [E0248]
src/main.rs:17 fn decrease(decrement: Command::Decrement) {
                                      ^~~~~~~~~~~~~~~~~~
error: aborting due to 2 previous errors
如果我单独声明结构,并将结构包装在元组结构(正确的术语?)中,每个都在枚举中,那么我会得到预期的结果,但由于到处都是冗长和类似的类型名,我怀疑我误解了某些东西:

struct Increment {
    quantity: u32,
}

struct Decrement {
    quantity: u32,
}

enum Command {
    Increment(Increment),
    Decrement(Decrement),
}

fn process_command(command: Command) {
    match command {
        Command::Increment(increment) => increase(increment),
        Command::Decrement(decrement) => decrease(decrement),
    };
}

fn increase(increment: Increment) {
    println!("Increasing by: {}.", increment.quantity);
}

fn decrease(decrement: Decrement) {
    println!("Decreasing by: {}.", decrement.quantity);
}

fn main() {
    let input = "Add";
    let quantity = 4;

    let command: Command = match input {
        "Add" => Command::Increment(Increment { quantity: quantity }),
        "Subtract" => Command::Decrement(Decrement { quantity: quantity }),
        _ => unreachable!(),
    };

    process_command(command);
}
运行输出:

Increasing by: 4.

在共享相同名称的枚举类型(术语?)中包装结构真的是最好的解决方案吗<代码>命令::Increment(Increment{quantity:7})

是的,这是您在这一实现过程中获得的最好结果。枚举仅为一种类型;它的变体纯粹是变体,而不是类型

另一种选择是使用特征和泛型:

struct增量{
数量:u32,
}
结构减量{
数量:u32,
}
特质指令{
fn过程(self);
}
增量的impl命令{
fn过程(自我){
println!(“增加{}”,自我数量);
}
}
减量指令{
fn过程(自我){
println!(“减少{}”,自我数量);
}
}

当然,这不是直接的平行关系;如果您想存储可能不同类型的
命令
,您需要更改
过程
以采用
self:Box
&self
,并且您需要使用
Box
命令
,但这是另一种适合您需求的方法。就定义而言,它更纯粹。

关于这个,我不确定我是否真的理解了你的问题

enum Command {
    Increment (u32),
    Decrement (u32),
}

fn process_command(command: Command) {
    match command {
        Command::Increment(quantity) => increase(quantity),
        Command::Decrement(quantity) => decrease(quantity),
    };
}

fn increase(quantity: u32) {
    println!("Increasing by: {}.", quantity);
}

fn decrease(quantity: u32) {
    println!("Decreasing by: {}.", quantity);
}

fn main() {
    let input = "Add";
    let quantity = 4;

    let command: Command = match input {
        "Add" => Command::Increment (quantity),
        "Subtract" => Command::Decrement (quantity),
        _ => unreachable!(),
    };

    process_command(command);
}

我可能误解了您的简单示例,但请记住,您可以直接在enum上实现方法:

enum Command {
    Increment {quantity: u32},
    Decrement {quantity: u32},
}

impl Command {
    fn process(self) {
        match self {
            Command::Increment { quantity } => {
                println!("Increasing by: {}.", quantity)
            },
            Command::Decrement { quantity } => {
                println!("Decreasing by: {}.", quantity)
            },
        };
    }
}

fn main() {
    let input = "Add";
    let quantity = 4;

    let command: Command = match input {
        "Add" => Command::Increment { quantity: quantity },
        "Subtract" => Command::Decrement { quantity: quantity },
        _ => unreachable!(),
    };

    command.process();
}

我碰巧喜欢这个版本,因为它消除了
process\u command(command)

的冗余。您也可以保留原始类型,并直接给出增加/减少的数量,因为匹配已经提取了变量信息。有什么原因吗“枚举仅为一种类型;它的变体纯粹是变体,而不是类型。"? 在我看来,将变体视为类型是完全可以实现的。@xudifsd:乍一看似乎是这样,但当你开始考虑类型布局时,你会意识到这样做实际上会带来一些相当重要的问题。这不是无法克服的问题,但它肯定会导致令人惊讶的行为,因为变体本身的布局和枚举中的变体有很大的不同。@ChrisMorgan您能说出一些吗?五年后,有没有更好的方法?我正面临着与OP完全相同的问题,使用trait对我来说并不是一个解决方案。如果变量有很多字段,那么它就不那么吸引人,如果枚举中有你想在
增加
减少
中使用的方法,则情况更是如此。如果你有多个字段,无论如何,您都需要相应结构的
Impl
数量相同。我同意它不如结构灵活。我认为这是一个集中的
process\u命令
或几个分散的实现的问题。这两种情况都有利弊