Enums 如何查找枚举变量的参数数?

Enums 如何查找枚举变量的参数数?,enums,rust,Enums,Rust,我有一个枚举,它表示8080处理器上所有可能的指令。一条指令的长度可以是1、2或3字节,这取决于它是否有与其相关的信息以及有多少信息。例如: #[allow(non_camel_case_types)] enum Instruction { None, NOP, LXI_B_D16(u8, u8), STAX_B, INX_B, MVI_B_D8(u8), MVI_C_D8(u8), RRC, LXI_D_D16(u8, u

我有一个枚举,它表示8080处理器上所有可能的指令。一条指令的长度可以是1、2或3字节,这取决于它是否有与其相关的信息以及有多少信息。例如:

#[allow(non_camel_case_types)]
enum Instruction {
    None,
    NOP,
    LXI_B_D16(u8, u8),
    STAX_B,
    INX_B,
    MVI_B_D8(u8),
    MVI_C_D8(u8),
    RRC,
    LXI_D_D16(u8, u8),
    MVI_D_D8(u8),
    RAL,
    DCR_E,
    MVI_E_D8(u8),
    LXI_H_D16(u8, u8),
    SHLD(u16),
    LHLD(u16),
    // ...
}
在为指令分配内存地址时,我通过二进制文件逐个指令迭代,使用每条指令的长度来确保循环不会在指令中途到达,并给我带来垃圾。我使用一个巨大的匹配表达式执行此操作,该表达式返回一个包含正确指令及其长度的元组:

match value {
    0x00 => (Instruction::NOP, 1),
    0x01 => (Instruction::LXI_B_D16(d1, d2), 3),
    0x02 => (Instruction::STAX_B, 1),
    0x05 => (Instruction::DCR_B, 1),
    0x06 => (Instruction::MVI_B_D8(d1), 2),
    0x07 => (Instruction::RLC, 1),
    0x0e => (Instruction::MVI_C_D8(d1), 2),
    0x0f => (Instruction::RRC, 1),
    0x11 => (Instruction::LXI_D_D16(d1, d2), 3),
    0x19 => (Instruction::DAD_D, 1),
    // ...
}
这很难看,但我不想将这个长度数字关联到类型中,因为只有在解析文件时,它才真正重要

看起来我应该能够从变体的形状推断出指令的长度。任何没有参数的都是长度1,任何有一个u8参数的都是长度2,任何有一个u16或两个u8参数的都是长度3

我还没能想出如何通过编程得到这个形状。例如,我不能像调用数组或向量那样调用
len()


我不认为这是的重复,因为我不是在寻找一种方法来获取枚举中变量的数量,而是任何单个变量的参数数量。

如注释中所述,您可以编写一个宏来为自己编写代码

出于懒惰的考虑,我将枚举定义简化为始终使用括号。这不是必需的,只是简化了我的工作

一旦宏解析了枚举,我们就可以生成一个impl块,其中包含一个匹配每个变量的函数。我们将每个变量的参数传递给一个内部宏,该宏为我们执行计数。此函数返回每个变量中的元素数:

macro_rules! instructions {
    (enum $ename:ident {
        $($vname:ident ( $($vty: ty),* )),*
    }) => {
        enum $ename {
            $($vname ( $($vty),* )),*
        }

        impl $ename {
            fn len(&self) -> usize {
                match self {
                    $($ename::$vname(..) => instructions!(@count ($($vty),*))),*
                }
            }
        }
    };

    (@count ()) => (0);
    (@count ($a:ty)) => (1);
    (@count ($a:ty, $b:ty)) => (2);
    (@count ($a:ty, $b:ty, $c:ty)) => (3);
}

instructions! {
    enum Instruction {
        None(),
        One(u8),
        Two(u8, u8),
        Three(u8, u8, u8)
    }
}

fn main() {
    println!("{}", Instruction::None().len());
    println!("{}", Instruction::One(1).len());
    println!("{}", Instruction::Two(1,2).len());
    println!("{}", Instruction::Three(1,2,3).len());

}
您也可以编写具有相同功能的

另见:


我认为这是不可能的,我也想知道您对这些信息做了什么。你不应该需要这个。似乎根本的问题更多的是关于消除重复。在Rust中实现这一点的一种方法是使用宏。您可以使用宏在生成大匹配表达式的同时生成指令枚举。@stargateur 8080 ROM(在我的例子中是“空间入侵者”)作为单个U8数组读入我的程序。每条指令的长度为1、2或3 u8:第一个u8表示指令类型,其余字节为相关数据。例如,JMP命令具有关联的u16内存地址以标记跳转位置。在解析这个数组时,我按指令字节进行迭代,因此我需要知道指令的长度,才能知道指针的增量。这可能是一种非常幼稚的做法,我不确定!