#Enum (defined i32) how to use the numerical value for computation ?

1 messages · Page 1 of 1 (latest)

ember abyss
#

I just want to start off by saying I'm very new to Rust and I'm currently in the early stages of learning and couldn't find a clear explanation on google.

I have an simple enum mapped to integers (not sure how enum with values are called). I'm trying to add a bunch of them together to figure out the count. I'm currently doing this by defining a value function, but this seems error prone to me since I need to repeat the mapping to values. Is there a better way of doing this ? I understand that I would need a function to convert from i32 to Result to account for numbers outside of my enum range, but I feel there must be something to do computation (similar to how I print the value using as i32. (sorry English is not my primary language)

example:

enum Result {
    Lose = -1,
    Draw = 0,
    Win = 1,
}
impl Result {
    fn value(&self) -> i32 {
        match &self {
            Result::Win => 1,
            Result::Draw => 0,
            Result::Lose => -1,
        }
    }
}

fn main() {
    let a = Result::Win;
    let b = Result::Lose;
    let c = a.value() + b.value();
    println!("results are a={} and b={} and c={}", a as i32, b as i32, c);
}

}
lilac ginkgo
#

cant you do this?rs let c = a as i32 + b as i32;

somber hill
#

You can, yes

ember abyss
#

oh yes it works! thanks! I didn't realized it worked because I was getting compilation errors : use of moved value a which doesn't happen with my value() function

#

I think I need to implement the Copy trait if I want to pass the values around instead of the reference, does that make sense ?

lilac ginkgo
#

btw you probably should not name the enum Result, because that's the same name as an extremely common enum used to represent either a successful output or an error

#

I'd probably name it Outcome

ember abyss
#

Good call, I'm trying some advent of code problems using Rust to learn it, I didn't read about the "annotations" yet (if that's what they are called)

#

I didn't know you could do things like that before...I'm assuming Enum don't implement Copy by default because they can be more complex than integer

lusty belfry
#

Well, in this case, they aren't, as they are just representing integers, but a limited range in this case.

Otherwise, nothing in Rust has any associated implementations by default, which is why the #[derive(...)] annotation exists as a shorthand, for reducing the boilerplate required for simple, repetitive implementations,

lilac ginkgo
ember abyss
#

Yeah, it makes sense now...I was passing my enums to function using &a, &b to get around the borrow checker...I knew it wasn't making a lot of sense passing a reference to a simple int

ember abyss
lilac ginkgo
#

the name for #[...] and #![...] syntax in general is called attributes

#

but you wont really learn anything by searching for "rust attributes", youll only get the syntax I think

#

derive macros are their own thing that happens to use that syntax

ember abyss
#

Just to confirm, let's say I now have an i32 e.g. let d :i32 = 0 I will need to implement a function from_i32 with match to get the Result right ?

    let d: i32 = 0;
    let e = d as Result; // this wouldn't work
lilac ginkgo
#

yeah

lusty belfry
#

Enums only covering a limited range of variants, so not every value would be a valid option to implicitly cast back...

ember abyss
#

yeah that's what I thought, thanks

lilac ginkgo
#
impl TryFrom<i32> for Outcome {
    type Error = ();

    fn try_from(value: i32) -> Result<Self, Self::Error> {
        match value {
            1 => Ok(Outcome::Win),
            0 => Ok(Outcome::Draw),
            -1 => Ok(Outcome::Lose),
            _ => Err(())
        }
    }
}```
#

now you could use Outcome::try_from(value) and handle the error

#

you could just make it a normal associated function, but theres a trait for it so why not implement the trait

lusty belfry
#

Alternatively, the value produced could be an Option.

ember abyss
#

I need to read on Type now lol ... is there a way to cast + handle the error without repeating all possible options in the match ?

lusty belfry
ember abyss
#

Let's say someone changes Win to =2, they need to think about changing the from function too (obviously this could be tested) but hypothetically

#

ok thanks

lilac ginkgo
lusty belfry
#

This was highlighed in another post, though I don't recall the name of the crate...

#

The post was created by a user attempting to transpose idioms from TypeScript...

ember abyss
#

It is not a big deal to have to change it in both places I think

#

I might be able to make something once I know rust better

lilac ginkgo
#

lib.rs is a website with a better search engine for crates than what crates.io has

#

I just seached for "enum" and thats the second result

ember abyss
#

My current use case was for the second part of the day2 of advent of code, I am am given the opponent's rock, paper, scissor Pick and the outcome I need to create.
e.g. He plays Rock, I need to Win

My implementation was :

enum Pick {
    Rock = 0,
    Paper = 1,
    Scissor = 2,
}

enum Outcome{
    Lose = -1,
    Draw = 0,
    Win = 1,
}
...
    let opponent_pick = Pick::Rock as i32;
    let outcome = Outcome::Win as i32;
    try_from((opponent_pick  + outcome  + 3) % 3) // this needed to be cast back to Pick
lilac ginkgo
#

wait why does toml crate not show up in lib.rs search

lusty belfry
ember abyss
lusty belfry
#

Yes, and you could still case it to an integer,

#

In most cases, enums will probably be union enums (like Result and Option), meaning they can't be cast to their integer representations, but if not, you can, whether or not you add explicit variant discriminators,

ember abyss
#

ok good to know, I read the enum section where they show more complex enum like IP address, it is neat. In my case it was mostly for the mental model... Opponent plays Rock (0), I need to draw (0) so I need to play Rock (0 + 0 = 0), Opponent plays Rock (0), I need to win (1) so I need to play Paper (0 + 1 = 1), etc.