枚举

类C的枚举类型会在内存里存成整型,且Rust会用最小的能够存放的类型来存。可以用#[repr]指定其内存形式。使用的时候用as进行类型转换也是可以的。但是不能从其它类型转成枚举,只能自己写转换逻辑或者使用crate enum_primitive

对应结构体,枚举的成员也有三种类型:结构体型,元组型和单元型。
成员的可见性和枚举本身一致。

在内存里,有数据的enum会保存一个小整型作为标签,加上能够容纳最大的成员的内存。标签是给Rust内部用来识别是哪个成员的。但Rust不保证内存结构。

  1. use std::collections::HashMap;
  2. enum Json {
  3. Null,
  4. Boolean(bool),
  5. Number(f64),
  6. String(String),
  7. Array(Vec<Json>),
  8. Object(Box<HashMap<String, Json>>),
  9. }

上例中使用Box是为了让内存更紧致(compact,压缩,整齐),因为enum在内存里要能放下最大的那个成员,如果不用指针而是放实际的对象,则会占用很大的内存。

在泛型枚举(generic enum)中,像Option如果T是引用或smart pointer,Rust可以省略标签字段,因为可以通过指针是否存在来判断是那个成员,如果是0就是None,如果有值就是Some(T),程序需要先判断,所以也会出现空指针。

模式

Pattern type Example Notes
Literal 100
“name”
Matches an exact value; the name of a const is also allowed
Range 0 ..= 100
‘a’ ..= ‘k’
Matches any value in range, including the end value
Wildcard _ Matches any value and ignores it
Variable name
mut count
Like _ but moves or copies the value into a new local variable
ref variable ref field
ref mut field
Borrows a reference to the matched value instead of moving or copying it
Binding with subpattern val @ 0 ..= 99
ref circle @ Shape::Circle { .. }
Matches the pattern to the right of @, using the variable name to the left
Enum pattern Some(value)
None
Pet::Orca
Tuple pattern (key, value)
(r, g, b)
Array pattern [a, b, c, d, e, f, g]
[heading, carom, correction]
Slice pattern [first, second]
[first, _, third]
[first, .., nth]
[]
Struct pattern Color(r, g, b)
Point { x, y }
Card { suit: Clubs, rank: n }
Account { id, name, .. }
Reference &value
&(k, v)
Matches only reference values
Multiple patterns ‘a’ | ‘A’ In refutable patterns only (match, if let, while let)
Guard expression x if x * x <= r2 In match only (not valid in let, etc.)

匹配结构的时候可以用..省略不关心的字段。
匹配切片的时候不仅匹配值还可以匹配长度,..也可以用来省略元素。

match的值在匹配的分支会转移不能Copy的类型,使用ref可以借用引用,而不转移。

  1. #[derive(Debug)]
  2. struct S {
  3. a: String,
  4. b: String
  5. }
  6. fn main() {
  7. let s = S {a: "1".into(), b: "2".into()};
  8. match s {
  9. S{ref a, ref b} => println!("{}, {}", a, b),
  10. _ => {}
  11. }
  12. println!("{:#?}", s) // 如果不用ref这里会报错:borrow of partially moved value: `s`
  13. }

可见match本身并不会转移,而是在具体的分支才会,但如果match处就借用&s,分支处也不用ref了。(因为有Binding modes,如果match的本身是引用,匹配到变量会自动变成引用)
ref mut可以从匹配分支获取可变引用。

匹配条件里的变量是重新声明的,会shadow其它同名的变量。

match条件后还可以再家if判断来进行更具体的判断,被称为match guard。
|可以表示或,在一个条件中匹配其中一个就算匹配。
..=用来匹配范围:1..=9'a'..='z',开区间匹配是不允许的。
@用来给匹配赋值s1 @ S{..} =>x @ 1..=9 =>

模式匹配还可以用来,定义变量,传递参数,for循环。用来解构struct,tuple和map。用在这些地方的模式只能是irrefutable的,matchif letwhile let中可以用refutable的。