Как правильно написать оператор сопоставления для перечисления с уже определенными структурами? - PullRequest
0 голосов
/ 18 марта 2020

Я хочу, чтобы перечисление действовало как вариант с ранее определенной структурой:

pub struct Element {
    symbol: String,
    atomic_number: u8,
    atomic_mass: f32,
}
pub struct Hydrogen {
    element: Element,
}
pub struct Helium {
    element: Element,
}
pub struct Lithium {
    element: Element,
}
pub enum ElementKind {
    HYDROGEN(Hydrogen),
    HELIUM(Helium),
    LITHIUM(Lithium,
}

impl Default for Hydrogen {
    fn default() -> Self {
        Hydrogen {
            element: Element {
                symbol: "H".to_string(),
                atomic_number: 1,
                atomic_mass: 1.008,
            },
        }
    }
}

impl Default for Helium {
    fn default() -> Self {
        Helium {
            element: Element {
                symbol: "He".to_string(),
                atomic_number: 2,
                atomic_mass: 4.003,
            },
        }
    }
}

impl Default for Lithium {
    fn default() -> Self {
        Lithium {
            element: Element {
                symbol: "Li".to_string(),
                atomic_number: 3,
                atomic_mass: 6.491,
            },
        }
    }
}

fn main() {
    let e = ElementKind::HYDROGEN;
    match e {
        // TODO
    }
}

Как правильно написать оператор match, чтобы, например, всегда печатать symbol элемента?

1 Ответ

3 голосов
/ 18 марта 2020

Когда вы пишете

struct Foo {
    foo: u32,
}

enum Bar {
    Foo,
}

, между структурой Foo и вариантом Bar::Foo нет абсолютно никакой связи. Они просто имеют одно и то же имя. (См. Также Есть ли способ использовать существующие структуры в качестве вариантов enum? ).

Обычным способом решения этой проблемы было бы наличие поля в варианте :

enum Bar {
    // The first Foo is the variant name, the second Foo a field of type Foo
    Foo(Foo),
}

или для включения структуры в перечисление (то есть используйте вариант struct):

enum Bar {
    Foo {
        foo: u32,
    }
}

Однако в вашем случае я считаю, что вам не нужно создать структуру для каждого элемента и выполнить следующие действия:

#[derive(Debug)]
pub struct Element {
    symbol: String,
    atomic_number: u8,
    atomic_mass: f32,
}

pub enum ElementKind {
    Hydrogen,
    Helium,
    Lithium,
}

impl From<ElementKind> for Element {
    fn from(e: ElementKind) -> Element {
        use ElementKind::*;

        match e {
            Hydrogen => Element {
                symbol: "H".to_string(),
                atomic_number: 1,
                atomic_mass: 1.008,
            },
            Helium => Element {
                symbol: "He".to_string(),
                atomic_number: 2,
                atomic_mass: 4.003,
            },
            Lithium => Element {
                symbol: "Li".to_string(),
                atomic_number: 3,
                atomic_mass: 6.491,
            },
        }
    }
}

fn main() {
    let e = ElementKind::Hydrogen;
    println!("{:#?}", Element::from(e));
}

( Постоянная ссылка на игровую площадку )

Действительно, с вашим решением каждый экземпляр ElementKind будет содержать избыточную информацию: сам вариант (которого достаточно для идентификации элемента) и его данные (которого также достаточно для идентификации элемента).

...