Codes in lesson10
不同语言 enum 对比
typescript
1 2 3 4 5 6 7
| enum Direction { North, East, South, West } let dir: Direction = Direction.North;
|
c++
1 2 3 4 5 6 7 8 9
| enum Direction { North, East, South, West } int main() { Direction dir = North; }
|
rust
1 2 3 4 5 6 7
| enum Direction { North, East, South, West } let dir: Direction = Direction::North;
|
enum 语法
field-less enum
只定义类型,但没有定义值
1 2 3 4 5
| enum Fieldless { Tuple(), Struct {}, Unit, }
|
unit-only enum
全都是 unit 类型
1 2 3 4 5
| enum UnitOnlyEnum { Foo = 0, Bar = 1, Baz = 2, }
|
enum 规范
Pascal Case
enum 名和 enum 值采用 Pascal Case
1 2 3 4 5
| enum PascalCase { PascalCase1, PascalCase2, PascalCase3, }
|
snake_case
函数或关联函数采用 snake_case
1 2 3 4 5 6 7 8 9 10 11 12 13
| impl Pets { fn snake_case1(&self) { println!("hi"); } }
impl Pets { fn snake_case2(name: String) { println!("name is {name}"); } }
|
enum 用法
match
match 必须能匹配所有条件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| enum Pets { Cat, Dog, } let cat = Pets::Cat; let dog = Pets::Dog; match cat { Pets::Cat => { println!("is cat"); } Pets::Dog => { println!("is dog"); } _ => {} }
|
if let
1 2 3
| if let cat = Pets::Cat { println!("is cat"); }
|
option & result
option
- 表示一个值可能为 Some(存在)或 None(不存在)
- 替代其他语言中的 null 或 undefined,强制开发者处理可能的空值
1 2 3 4 5 6
| let num = Some(1); let none: Option<usize> = None; match num { Some(val) => {} None => {} }
|
result
- 表示一个操作可能成功(Ok)或失败(Err)
- 替代其他语言中的异常(Exception),强制开发者处理可能的错误
1 2 3 4 5 6 7 8 9
| fn main() -> Result<(), ()> { let num: Result<usize, ()> = Ok(1); match num { Ok(val) => {} Err(_) => {} } Ok(()) }
|
option 和 result 的转换
option -> result: ok_or
当 Option 的 None 需要携带具体的错误信息时(例如在函数中需要返回 Result,但内部逻辑依赖 Option)
1 2 3 4
| let opt: Option<i32> = Some(42); let result: Result<i32, &str> = opt.ok_or("error"); let none: Option<i32> = None; let result: Result<i32, &str> = none.ok_or("error");
|
result -> option : ok(), err()
当错误无关紧要,只需关注操作是否成功时(例如日志记录或快速判断)
1 2 3 4
| let res: Result<i32, &str> = Ok(42); let opt: Option<i32> = res.ok(); let res: Result<i32, &str> = Err("error"); let opt: Option<i32> = res.ok();
|
常用 API
Option API
.map() .unwrap()
map() 对 Option 中的值应用一个闭包,返回一个新的布尔值 Option。若原 Option 是 None,直接返回 None
.unwrap() 取值,如果是 None 则会 panic
1 2 3
| let opt: Option<i32> = Some(1); let a1 = opt.map(|num| num > 0); assert!(a1.unwrap());
|
.and_then()
.and_then() 对 Option 中的值应用一个闭包,闭包返回新的 Option,实现链式调用。若原 Option 是 None,直接返回 None
1 2 3
| let opt: Option<i32> = Some(1); let b1 = opt.and_then(|val| Some(val + 1)); assert_eq!(b1, Some(2));
|
.or_else()
.or_else() 在 Option 为 None 时调用闭包生成一个替代的 Option。若原 Option 是 Some,直接返回原值
1 2 3
| let opt: Option<i32> = Some(1); let c1 = opt.or_else(|| Some(2)); assert_eq!(c1, Some(1));
|
Result API
.map()
.map() 对 Result 中的 Ok 值应用一个闭包,返回新的 Result。若原 Result 是 Err,直接返回原 Err
1 2 3
| let ret: Result<i32, &str> = Ok(1); let a2 = ret.map(|val| val > 0); assert!(a2.unwrap());
|
.and_then()
.and_then() 对 Result 中的 Ok 值应用一个闭包,闭包返回新的 Result,实现链式调用。若原 Result 是 Err,直接返回原 Err
1 2 3
| let ret: Result<i32, &str> = Ok(1); let b2 = ret.and_then(|val| Ok((val + 1))); assert_eq!(b2, Ok(2));
|
.or_else()
.or_else() 在 Result 为 Err 时调用闭包生成一个替代的 Result。若原 Result 是 Ok,直接返回原值
1 2 3
| let ret: Result<i32, &str> = Ok(1); let c2 = ret.or_else(|str| Err(3)); assert_eq!(c2, Ok(1));
|
enum 内存占用
每个 enum 包含标签(tag)和数据(data)两部分:
- 标签:用于区分不同变体,大小取决于变体数量
- 比如:1 byte = 8 bits,能表示 2^8=256 个变体
- 数据:存储变体中的具体值,大小由最大的变体决定 - 因为每次当枚举变量被赋值为某个变体时,只有该变体的数据会被写入内存,而旧数据会被销毁
课后习题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| enum MyEnum { A(u8, u8), B, C {}, }
println!("size of MyEnum: {}", size_of::<MyEnum>());
enum EnumA { A = 255, }
println!("size of EnumA: {}", size_of::<EnumA>());
enum EnumB { A = 255, B, }
println!("size of EnumB: {}", size_of::<EnumB>());
|