首页 > 解决方案 > 枚举之间一对一映射的穷举性检查

问题描述

我正在编写一些基本的生物信息学代码来将 DNA 转录为 RNA:

pub enum DnaNucleotide {
    A,
    C,
    G,
    T,
}

pub enum RnaNucleotide {
    A,
    C,
    G,
    U,
}

fn transcribe(base: &DnaNucleotide) -> RnaNucleotide {
    match base {
        DnaNucleotide::A => RnaNucleotide::A,
        DnaNucleotide::C => RnaNucleotide::C,
        DnaNucleotide::G => RnaNucleotide::G,
        DnaNucleotide::T => RnaNucleotide::U,
    }
}

有没有办法让编译器也在语句的右侧进行详尽检查match,基本上确保两个枚举之间的 1-1 映射?

(一个相关问题:上面可能用某种双射映射更好地表示,但我不想失去详尽检查。有更好的方法吗?)

标签: rustenumsone-to-one

解决方案


两个枚举之间存在一一对应的事实表明您实际上应该只在幕后使用一个枚举。这是我认为适合您需求的数据模型示例。这自然是详尽无遗的,因为只有一个枚举开始。

use core::fmt::{Debug, Error, Formatter};

enum NucleicAcid {
    Dna,
    Rna,
}

enum Nucleotide {
    A,
    C,
    G,
    TU,
}

struct BasePair {
    nucleic_acid: NucleicAcid,
    nucleotide: Nucleotide,
}

impl BasePair {
    fn new(nucleic_acid: NucleicAcid, nucleotide: Nucleotide) -> Self {
        Self {
            nucleic_acid,
            nucleotide,
        }
    }
}

impl Debug for BasePair {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
        use NucleicAcid::*;
        use Nucleotide::*;

        let BasePair {
            nucleic_acid,
            nucleotide,
        } = self;
        let nucleic_acid_str = match nucleic_acid {
            Dna => "dna",
            Rna => "rna",
        };
        let nucleotide_str = match nucleotide {
            A => "A",
            C => "C",
            G => "G",
            TU => match nucleic_acid {
                Dna => "T",
                Rna => "U",
            },
        };
        f.write_fmt(format_args!("{}:{}", nucleic_acid_str, nucleotide_str))
    }
}

fn main() {
    let bp1 = BasePair::new(NucleicAcid::Dna, Nucleotide::TU);
    let bp2 = BasePair::new(NucleicAcid::Rna, Nucleotide::C);
    
    println!("{:?}, {:?}", bp1, bp2);
    // dna:T, rna:C
}

推荐阅读