Hello.
I love Zig’s enum type that gives us the wonderful exhaustive check of switch. However, I sometimes want to try to convert an integer that has no value in the enum type:
When I pass 3 to handleFruit(), it leads to a panic in Debug build and UB in Release build. I want some method that converts an integer to the enum, but returns an error or something when it cannot, like:
const result: ?Fruit = if (tryEnumFromInt(index)) |fruit| fruit else null;
In my case, my enum type has enormous values. My code takes an integer from user inputs, converts them into the enum type, and then handle them in a switch. But I don’t have to implement all the values and can just ignore when it is allowed, though I plan to implement some of the unhandled enum values in the near future.
Note that my enum has “gaps” between its values:
enum (u32) {
first = 0,
second = 3,
third = 9,
};
So I cannot check the input by comparing the minimum and maximum values of the enum using @typeInfo().
If I pass a comptime value not in the enum to std.mem.intToEnum(), it becomes compile error (it is desirable). But if index is a runtime-value, it worked perfectly for me. (Am I misunderstanding something…?)
Using _ instead of else in the switch statement means that your switch has to handle all known values of the enum, so when you add more later, you have to add them to all exhaustive switches or it won’t compile.
Using std.meta.intToEnum and treating unknown values as an error might work, but a non-exhaustive enum with a _ prong is idiomatic here, when you say this:
An unknown value isn’t really an error, is it? The big difference is that if an unknown value is given to std.meta.intToEnum it will throw/return an error{IntToEnumError}, but using _ will give you a properly-typed enum value for the unknowns, you can log them, convert them to the backing integer and switch on that, there are a lot of options which you don’t get from treating them as an error condition.
Mostly I wanted to convey that you can still do exhaustive switching with a non-exhaustive enum, because a _ prong still requires you to handle all named values explicitly.
Wow, I didn’t know non-exhaustive enum! That seems a little bit more preferable in my situation.
I have to read the whole Zig documentation again. It has much valuable features that I don’t know…
I’m sorry but I’ve changed the “solution” to mnemnion’s answer.