Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sharing a common value in all enum values

Tags:

enums

rust

I have the following code where every variant of the enum Message has a Term value associated with it:

type Term = usize;
pub enum Message {
    AppendRequest(Term),
    AppendResponse(Term),
    VoteRequest(Term),
    VoteResponse(Term),
}

impl Message {
    pub fn term(&self) -> Term {
        match *self {
            Message::AppendRequest(term)  => term,
            Message::AppendResponse(term) => term,
            Message::VoteRequest(term) => term,
            Message::VoteResponse(term) =>term,
        }
    }
}

I want to, given a Message be able to get its term without having to deconstruct the actual Message value I have. The best I could come up with was creating a public function that unpacked the value for me, but this feels clunky. If I ever add a new enum value, I'm going to have to remember to update match statement in the term function.

Is there a more succinct/ergonomic way to express the code above? Is there some way to say "hey, every value for this enum will have also have a Term value associated with it.

like image 572
Kurtis Nusbaum Avatar asked Mar 09 '18 04:03

Kurtis Nusbaum


People also ask

Can enums have the same value python?

By definition, the enumeration member values are unique. However, you can create different member names with the same values.

Can we assign value in enum?

You can assign different values to enum member. A change in the default value of an enum member will automatically assign incremental values to the other members sequentially. You can even assign different values to each member.

Can you cast enum Java?

You can't ; but you can create a static method in your enums, with a translation code. But you must have a clear idea of the rules you want to implement.

Is there a limit to the number of values you can have in a enum?

In theory, an ENUM column can have a maximum of 65,535 distinct values; in practice, the real maximum depends on many factors.


2 Answers

Is there some way to say "hey, every value for this enum will have also have a Term value associated with it.

No. This is usually handled by splitting the enum into two parts, with a struct containing all the common parts:

pub struct Message {
    term: Term,
    kind: MessageKind,
}

pub enum MessageKind {
    AppendRequest,
    AppendResponse,
    VoteRequest,
    VoteResponse,
}
like image 181
DK. Avatar answered Oct 14 '22 14:10

DK.


One option is to implement the Deref (and/or DerefMut) trait to convert to the common part.

You still have to update that implementation each time you add to the Enum, but there is less boilerplate at the point of use.

E.g., an example below, note that main accesses the field number on the Enum.

use std::ops::Deref;
use std::string::String;

enum JudgedNumber {
    GoodNumber(Number),
    BadNumber(Number, String),
}

struct Number { number: i32 }

fn main() {
    let nice = JudgedNumber::GoodNumber(Number{number: 42});
    let naughty = JudgedNumber::BadNumber(
        Number{number: 666}, "Damn you to hell".to_string());
    println!("j1 = {}", j1.number);
    println!("j2 = {}", j2.number);
}

impl Deref for JudgedNumber {
    type Target = Number;
    fn deref(&self) -> &Number {
        match self {
            JudgedNumber::GoodNumber(n) => n,
            JudgedNumber::BadNumber(n, _) => n,
        }
    }
}

I learnt this from https://github.com/rust-embedded/svd/blob/master/src/svd/cluster.rs

like image 25
user1998586 Avatar answered Oct 14 '22 15:10

user1998586