How do I specify that a value in a struct must be one of a fixed number of possible values?

I want to ensure that the value of a field is always only one of a fixed range of possible values.

Is this the right way to do such a thing?

const STATES: [String] = ["DEAD", "PROCESSING", "ACCEPTED", "DELETED", "NOTACCEPTED"];

pub struct MyStruct {
    id: String,
    state: STATES,
}

thanks!

Use an enum.

5 Likes

No, you should define an enum:

pub enum State {
    Dead,
    Processing,
    Accepted,
    Deleted,
    NotAccepted,
}

pub struct MyStruct {
    id: String,
    state: State,
}

See the book chapter for more details

2 Likes

I had thought that an enum would result in a number being stored rather than a string.

So say for example I change the enum then the stored numbers would be wrong.

But in thinking about it, maybe that would be an issue in a database lookup where the values have a number key, but perhaps not the same issue as in compiled Rust because it's all in memory.

Am I thinking in the right direction to understand this? Basically that the "num" part of enum is not really relevant.

I don't think you need to worry about how the enum is represented in memory. If you need a String representation of each state, you can implement From<State> for String or some other conversion method.

impl From<State> for String {
    fn from(state: State) -> String {
        match state {
            State::Dead => "Dead".to_owned(),
            // ...
        }
    }
}
1 Like

I would probably choose &'static str as the return type here, and definitely use an inherent method rather than a From impl, but otherwise endorsed.

6 Likes

Agreed. That's a better choice.

1 Like

Can the enum definition be inlined in the struct?

I just tried this in my IDE and did not like it:

pub struct MyStruct {
    id: String,
    state: {Dead, Processing,  Accepted, Deleted,  NotAccepted},
}

Nor did it like:

pub struct MyStruct {
    id: String,
    state: enum {Dead, Processing,  Accepted, Deleted,  NotAccepted},
}

No, you have to declare it separately. I think there have been some RFCs related to anonymous enums, but I don't know if they relate to this situation.

1 Like

Could you please elaborate on why returning &'static str would be better? I guess that it would be more flexible, but would like to hear your thoughts on this.

If your function can only ever return string literals, &'static str is the most natural return type, the one that best expresses your intent in writing the function. It also saves a heap allocation (in String::to_owned) without complicating the code any, which never hurts. Finally, while it's easy to get a String from a &'static str, the inverse requires leaking an allocation, which is unidiomatic at best, so (as you noted) returning &'static str gives more flexibility to the caller.

2 Likes

Agreed. I wasn't really thinking when I wrote my earlier post. I just saw "needs string from state" and jumped to the first solution that came to mind.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.