I decided to implement a protocol which uses a couple of flags, so I started to define enum
s for the flags. However, when I want to define a flag that has two values which can be true
or false
I get an error message:
// The protocol definition says that the flag
// can have two values true or false, so I could just use
// plain bool, but I want another name for true and false.
enum Flag {
ONE = true,
TWO = false,
}
error[E0308]: mismatched types
--> src/lib.rs:5:11
|
5 | ONE = true,
| ^^^^ expected isize, found bool
error[E0308]: mismatched types
--> src/lib.rs:6:11
|
6 | TWO = false,
| ^^^^^ expected isize, found bool
The reason I want to use an enum instead of two constants is that the flag is not an bool. It is flag with representation value true or false, but I don't want to mix normal bool
s and flag. If I used bool
constants, I could pass the flag value to every function that takes a bool
as argument, or use them in expressions as bool
, e.g.
if ONE {
}
fn some_function_with_a_flag(b: bool);
// I don't want this!
some_function_with_a_flag(ONE);
Using an enum instead of bool constants also prevents some more errors when using the flag as a struct member. There are more flags defined in the same way, so when I just use plain bool
s and constants I will have a struct like
struct Header {
flag1: bool,
flag2: bool,
flag3: bool,
}
The compiler will accept code where the flag values are switched:
h = Header { flag3: ONE, flag1: TWO, flag2: ONE };
That is not possible when each flag is its own type (alias for bool
).
The point of defining the enum with values true
and false
is just that the protocol defines it that way. In my code, I will probably only use the boolean value of the flags when data is packed to be serialized (it is part of the data header).
Ok, the compiler always assumes that the underlying type is isize
. It could derive it from the values, but let's define it
#[repr(bool)]
enum E1 {
ONE = true,
TWO = false,
}
error[E0552]: unrecognized representation hint
--> src/lib.rs:1:8
|
1 | #[repr(bool)]
| ^^^^
It looks like I have to use u8
as the underlying type and then always cast the value into bool
#[repr(u8)]
enum E2 {
ONE = 1,
TWO = 0,
}
let x = E2::ONE as bool;
This compiles, but seems overly complicated. Is there a better way to define an enum
with bool
values? Is there an idiom for a type alias of bool
where I can specify the value? I could just do
enum Flag {
TWO,
ONE,
}
but now I again have to cast the value to bool
all the time, and the order of definition looks unnatural.
Since the bool value will only be used when reading/writing the header I will just put the conversion into the corresponding functions and keep the rest of the program free from implementation details.
#[repr(u8)]
to get your enum represented as a single byte; the compiler already does that if the discriminants are in bounds, whether the discriminants are explicit or implicit. – Francis Gagnéu8
as the underlying type and then always cast the value intobool
[...] This compiles, but seems overly complicated." Do you want to be able to assign abool
to aFlag
or not? If puttingas bool
is "overly complicated", then how could you remove that without making it possible to accidentally mixFlag
s andbool
s? – trentcl