Coming from C, I knew enums as ... well, enumerations. For example, I have this in my window manager: enum IPCCommand { IPCClientCenterFloating = 0, IPCClientClose, IPCClientFloatingToggle, IPCClientFullscreenToggle, IPCClientKill, ... } So they are basically just names for numeric values with some little extra bonuses like "switch" being able to check that you really covered all possible variants of an enum. Now, when you start learning Rust, you'll been confronted very soon with the fact that Rust enums can "contain values". Wait, what? Is this the same thing as the "0" in the example above? How ... what? :) Lots of confusion. It gets a little better once you understand the common practice of returning enums from functions -- which act as a way to tell the caller whether the function has failed or not. Take this example (it's from ): fn divide(numerator: f64, denominator: f64) -> Option { if denominator == 0.0 { return None; } else { return Some(numerator / denominator); } } let result = divide(2.0, 3.0); match result { Some(x) => println!("Result: {}", x), None => println!("Cannot divide by 0"), } "Option" is an enum. It's defined like this: pub enum Option { None, Some(T), } Boom, there's the additional confusion of "generics", let alone the "destructuring" that happens in the "match" statement above. Long story short, that function above returns an enum and that enum is either "None" or "Some" (those are the "variants" of the enum). But when it's "Some", the enum also contains a *value* -- here it's the result of the division. I wasn't really convinced by this. The approach of Go is much simpler and much easier to understand (sorry if this is bad code, I don't really write programs in Go): func divide(numerator float64, denominator float64) (float64, error) { if denominator == 0.0 { return 0, errors.New("Cannot divide by 0") } else { return numerator / denominator, nil } } func main() { result, err := divide(1.0, 0.0) if err != nil { fmt.Printf("Error: %v\n", err) } else { fmt.Printf("Result: %f\n", result) } } You return a tuple and, if "err" is not "nil", there was an error. Simple. It took me quite a while to appreciate that I can directly attach values to enum variants in Rust. And here's my use case for it: As mentioned in previous posts, I'm writing a simple "ls" in Rust (as an exercise, I'll probably never publish this). I want to print the file names in a directory, line by line. I also want a separator line between directories and files. It shall look something like this: $ l drwx------ 2 void users 160 09-26 09:40 | ./ drwxrwxrwt 22 root root 500 09-26 09:43 | ../ -----------------------------------------------+--------------------------------- -rw-r--r-- 1 void users 655'360 09-26 06:37 | 2021-09-25--katriawm-rust-ls.png -rwxr-xr-x 1 void users 1'779'739 09-26 09:40 | test* -rw-r--r-- 1 void users 431 09-26 09:40 | test.go -rwxr-xr-x 1 void users 16'872 09-26 08:21 | vec* -rw-r--r-- 1 void users 1'322 09-26 08:21 | vec.c -rw-r--r-- 1 void users 1'521 09-26 08:23 | vec.h Internally, this originally was a "Vec>": A two-dimensional table. Put another way, one line is a "Vec" (a list of the values of the columns) and then you put all those individual lines into another list, thus forming a table. Notice the *vertical* separator line: The "|". Is it as simple as adding a "|" string? Could be. But then notice the *horizontal* separator line that has a "+" where both lines meet. I want my code to be generic, so that I can easily print it like this: $ l drwx------ 2 | void users | 160 09-26 09:40 | ./ drwxrwxrwt 22 | root root | 500 09-26 09:55 | ../ --------------+------------+-----------------------+--------------------------------- -rw-r--r-- 1 | void users | 655'360 09-26 06:37 | 2021-09-25--katriawm-rust-ls.png -rwxr-xr-x 1 | void users | 1'779'739 09-26 09:40 | test* -rw-r--r-- 1 | void users | 431 09-26 09:40 | test.go -rwxr-xr-x 1 | void users | 16'872 09-26 08:21 | vec* -rw-r--r-- 1 | void users | 1'322 09-26 08:21 | vec.c -rw-r--r-- 1 | void users | 1'521 09-26 08:23 | vec.h How do you implement that? How do you detect where the vertical lines are, in order to have the "+" drawn at the correct spot? When you just put a "|" into your "Vec", you are no longer able to distinguish this from a file called "|" (which is a legal file name). My current solution is to turn the "Vec>" into a "Vec>", where "Cell" is an enum: enum Cell { Text(String), Separator, } Now I can fill the vector like this: line.push(Cell::Text(format_size(entry.size))); line.push(Cell::Text(format_time(entry.mtime))); line.push(Cell::Separator); line.push(Cell::Text(format_name(&entry))); The cells of my table are either text or separators -- and the type system makes sure of that. We also get the additional bonus of "switch" statements (it's "match" in Rust) being able to detect if we have covered all possible values of this enum: for cell in line.iter() { let to_show = match cell { Cell::Text(my_string) => my_string, Cell::Separator => "|", }; print!("{} ", to_show); } print!("\n"); If I were to introduce a new type of cell at a later stage, the compiler would alert me if I didn't cover this case in all "match" statements. Very nice. (In reality, it's not a "Vec>" but a "Vec", where "Row" is another enum that distinguishes between horizontal separator lines and normal lines. It's the exact same thing.) Do you *need* enums with values in order to solve this problem? No. Check the Rust docs above, they list alternatives. Enums with values are mostly syntactic sugar. "Syntactic sugar" means: "Oh, it's easy once you understand it, but it makes life for newbies muuuuuuuuuuch harder."