60

I have an enum:

enum Foo {
    Bar = 1,
}

How do I convert a reference to this enum into an integer to be used in math?

fn f(foo: &Foo) {
    let f = foo as u8;  // error[E0606]: casting `&Foo` as `u8` is invalid
    let f = foo as &u8; // error[E0605]: non-primitive cast: `&Foo` as `&u8`
    let f = *foo as u8; // error[E0507]: cannot move out of borrowed content
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Vitaly Kushner
  • 9,247
  • 8
  • 33
  • 41

2 Answers2

85

*foo as u8 is correct, but you have to implement Copy because otherwise you would leave behind an invalid reference.

#[derive(Copy, Clone)]
enum Foo {
    Bar = 1,
}

fn f(foo: &Foo) -> u8 {
    *foo as u8
}

Since your enum will be a very lightweight object you should pass it around by value anyway, for which you would need Copy as well.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
A.B.
  • 15,364
  • 3
  • 61
  • 64
  • 1
    Expanding on this, without `Copy` the `*foo` is interpreted as moving the pointed-to value out of the shared reference passed to `f`. – dubiousjim Jan 22 '21 at 07:10
  • Is there a way to cast an `enum` to an `int` without implementing `Copy` on the `enum`? – Lukas Mar 14 '23 at 12:37
  • @Lukas Why do you need that? If you can cast it to an integer, the enum has no payload, so it is always possible to impl `Copy` for it. – Chayim Friedman Aug 14 '23 at 16:02
-3

The posts above are mistaken:

The enum Foo

  • as the variant name Bar
  • and the variant number 1. Rust does not require to set a number. But if you want to check the values e.g. from a database it makes sense to use (and control) the numer and not the name.

As I understood; you need the enum.value (value) of an enum variant

Here is a working solution for your example:

use std::fmt;

#[derive(Debug)]
enum Foo {
    Bar = 1,
}

//The to_string() method is available because, Rust automatically implements it for any type that implements Display.
impl fmt::Display for Foo { 
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self) // or fmt::Debug::fmt(self, f) // prints "Bar" NOT the value
    }
}

 // here are 2 strings, one for the Variant "Bar" and one for the value "1"

let value_of_foo_bar_enum_as_string:String=(Foo::Bar as i32).to_string();
let enum_variant_as_string:String=Foo::Bar.to_string(); //requires impl fmt::Display for Foo above

println!("Enum Foo: variant ->{}<- has value ->{}<-", Foo::Bar, (Foo::Bar as i32).to_string());
// or 
println!("Enum Foo: variant ->{enum_variant_as_string}<- has value ->{value_of_foo_bar_enum_as_string}<-");

// Both prints out "Enum Foo: variant ->Bar<- has value ->1<-

assert_eq!(Foo::Bar.to_string(),"Bar");
assert_eq!((Foo::Bar as i32).to_string(),"1"); // default is i32, can be replaced with u8

Have fun! Martin

mzach
  • 1
  • 1