3

Say I have

enum Grades { A, B, C, D, E, F }

Then I can easily use the associated value for each grade with

Grades::C as u32

However, there seems to be no opposite way. I understand that, in general, this would be a partial function, as, for example

42 as Grades

makes no sense. However, what is the idiomatic way to do this? Is it

impl From<u32> for Grades { ... }

with a panic! if the argument is invalid? Or even

impl From<u32> for Option<Grades> { ... }

A related question, is there something like an Enum trait? As the need to convert between integer and enumerations often arises because (to my bloody beginner knowledge) there is apparently nothing that provides the functionality of Haskells Enum and Bounded typeclasses. Hence, if I need a range of Grades B..E, or the next Grade (succ B) or the previous Grade (pred E) I feel out of luck.

(The suggested question doesn't answer my question fully, since it occured to me that the deeper reason I need this functionality in the first place is most often "missing" enum functionality - that is, "missing" from the standpoint of a Haskell programmer. This is what the second part is all about.)

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Ingo
  • 36,037
  • 5
  • 53
  • 100
  • there are a lot of crate that offer macro to help – Stargateur Oct 08 '20 at 20:27
  • Does this answer your question? [How do I match enum values with an integer?](https://stackoverflow.com/questions/28028854/how-do-i-match-enum-values-with-an-integer) – trent Oct 08 '20 at 20:32
  • Combining two of the answers from that question, I would suggest deriving `FromPrimitive` from `num_traits` and then using `FromPrimitive` to implement `TryFrom for Grades` for whatever `I` types you like. – trent Oct 08 '20 at 20:33
  • 1
    As for your secondary question, the range operator `..` actually works for arbitrary types, so `B..E` compiles out of the box. If you want `.contains()` to work, you need to also derive `PartialOrd`. However, there's not really such a thing as a generic successor function in stable today. `Step` will probably be added eventually, but you'll still have to implement it manually. There are good reasons for this which this comment field is too short to go into. – trent Oct 08 '20 at 21:01
  • @trentcl Range doesn't work for me: PAWN..QUEEN gives compiler error "the trait `std::iter::Step` is not implemented for `position::Piece`" – Ingo Oct 08 '20 at 22:04

2 Answers2

1

There is a enum_primitive crate that exports a macro enum_from_primitive! that automatically derives FromPrimitive which seems to do what you want.

NovaDenizen
  • 5,089
  • 14
  • 28
1

Although the easiest solution is probably the enum_primitive crate (that has already been suggested), the idiomatic way to implement this yourself would be the TryFrom trait from the standard library. This is also very close to what you have already suggested in your question. The only difference is, that this returns a Result so that you don't have to panic! when a wrong input is given.

Niklas Mohrin
  • 1,756
  • 7
  • 23
  • 1
    I am not sure about your last paragraph. Transitive implementations of traits dont work because there often are multiple valid `impl` strategies and the compiler has no way to pick one of them. – NovaDenizen Oct 11 '20 at 16:11