Rust Enum
Table of Contents
1. Rust Enum
1.1. union
1.1.1. untagged union
union 分为两种: untagged union 及 tagged union.
c 语言的 union 是 untagged union:
union Data { int i; float f; char c[4]; }; int main(int argc, char *argv[]) { union Data x; x.i = 0x01020304; int i; for (i = 0; i < 4; i++) { printf("%x ", x.c[i]); } }
untagged, 是指 Data 本身没有保存数据的具体类型 (tag), 所以无法区分数据的类型.
1.1.2. tagged union
rust 的 enum 实际是 tagged union
#[derive(Debug)] enum Data { i(i32), f(i32), } fn main() { let x = Data::i(0x1234); println!("size: {:?}", std::mem::size_of::<Data>()); let pp = &x as *const _ as *const [i32; 2]; unsafe { println!("Data:i(0x1234): {:?}", (*pp)); } let x = Data::f(0x1234); let pp = &x as *const _ as *const [i32; 2]; unsafe { println!("Data:f(0x1234): {:?}", (*pp)); } }
size: 8 Data:i(0x1234): [0, 4660] Data:f(0x1234): [1, 4660]
可见 Data 的内存布局为 [tag, data], Data 的具体类型是做为 tag 保存在 Data 中
1.2. enum overview
enum Data { A, B(i32), C(i32, i32), D(Vec<i32>), } enum Data2<T> { A, B(T), } fn main() { let x = Data::D(vec![1, 2, 3]); let y = Data2::B(10); }
1.3. pattern matching
pattern matching 主要用来 match enum, 但可以用来 match 普通变量
fn test(x: i32) -> () { match x { 1 => println!("{:?}", 1), 2 | 3 | 4 | 5 => println!("{:?}", "2|3|4|5"), 6...7 => println!("{:?}", "[6..7]"), x if x >= 8 && x <= 9 => println!("{:?}", "x>8"), y => println!("other:{:?}", y), } } fn main() { for i in 1..=10 { test(i); } }
pattern matching 还可以用来 destructure struct 和 enum:
enum Data { A(i32, i32), B(String), } struct Test { x: i32, y: i32, } fn main() { match (Test { x: 1, y: 1 }) { Test { x, y: 1 } => { println!("Test with y=1"); } Test { x, y } => { println!("Test with {}:{}", x, y); } } match (Data::A(1, 1)) { Data::A(x, 1) => { println!("Data::A {}", x); } _ => (), } }
使用 ref 来 destructure struct
#[derive(Debug)] struct Test { s: String, } fn main() { let t = Test { s: "hello".to_owned(), }; match &t { &Test {ref s } => { println!("{:?}", s); } _ => (), } }
使用 `&` 来 destructure struct
struct Test(&'static i32); fn foo(x: i32) -> () { println!("{:?}", x); } fn main() { match Test(&10) { Test(&x) => { foo(x); } } }
`&x` 的实际上是把 `&10` 作 dereference 的结果赋值给 x, 因为 `&x match &10`
#[derive(Debug)] struct Inner(i32); struct Outer<'a>(&'a Inner); fn main() { let inner = Inner(10); match Outer(&inner) { Outer(&i) => { println!("{:?}", i); } } }
`&i` 会导致 `i=*(Outer.0)`, 因此编译报错, 因为 Outer.0 作为 borrowed content 无法被 `move out of Outer`