Rust (3)自定义类型
学习 Rust By Example 3. Custom Types
Rust 自定义类型有结构体(struct
)和枚举(enum
)。
结构体 Rust 的结构体有三种:
注意元组结构体用圆括号 ()
,有字段命名的结构体用花括号 {}
。
结构体可以通过解构,把字段绑定到变量:
1 2 let Pair(a, b) = pair; let Point{ x: x_edge, y: y_edge } = p;
结构体嵌套可以作为另一个的字段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #[derive(Debug)] struct Rectangle { top_left: Point, bottom_right: Point, } fn rect_area (rect: Rectangle) -> f32 { let Rectangle { top_left: Point { x: a, y: b }, bottom_right: Point { x: c, y: d }, } = rect; return (b - a) * (d - b); } fn main () { let rect = Rectangle { top_left: p, bottom_right: Point{x: 10.0 , y: 15.0 }, }; println! ("{:?}" , rect); println! ("{:?}" , rect.top_left.y); println! ("{:?}" , rect_area(rect)); }
解构或者构造结构体的时候,如果变量名
和字段名
相同,则可以把 name: name
简写为 name
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 fn square (top_left: Point, width: f32 ) -> Rectangle { let Point { x, y } = top_left; return Rectangle { top_left, bottom_right: Point { x: x + width, y: y + width, }, }; } fn main () { let s = square(Point { x: 1f32 , y: 1f32 }, 3f32 ); println! ("{:?}" , s); }
枚举 用 enum
创建一个枚举,通过 枚举名::种类
访问枚举值。
Rust 的枚举里面的成员是各种 struct,也就是说 Rust 的枚举和 Swift 类似,可以不止是一个值,还可以带上一些参数数据。
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 enum WebEvent { PageLoad, KeyPress(char ), Click { x: i64 , y: i64 }, } fn inspect (event: WebEvent) { match event { WebEvent::PageLoad => println! ("page loaded" ), WebEvent::KeyPress(c) => println! ("pressed '{}'" , c), WebEvent::Click { x, y } => { println! ("clicked at x={}, y={}" , x, y); } } } fn main () { let load = WebEvent::PageLoad; let pressed = WebEvent::KeyPress('x' ); let click = WebEvent::Click { x: 20 , y: 80 }; inspect(load); inspect(pressed); inspect(click); }
简单整数枚举 也可以不用那种复杂的带参数的,而只是简单的名字对应整数值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #[derive(Debug)] enum Numbers { Zero, One, Two, } #[derive(Debug)] enum Color { Red = 0xff0000 , Green = 0x00ff00 , Blue = 0x0000ff , } fn main () { println! ("{:?} is {}" , Numbers::Zero, Numbers::Zero as i32 ); println! ("{:?} is {:#08x}" , Color::Blue, Color::Blue as i32 ); }
类型别名 给类型取绰号,和 Go 语言类似:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #[derive(Debug)] enum VerboseEnumOfThingsToDoWithNumbers { Add, Subtract, } type Operations = VerboseEnumOfThingsToDoWithNumbers;impl Operations { fn run (&self , x: i32 , y: i32 ) -> i32 { match self { Self::Add => x + y, Self::Subtract => x - y, } } } fn main () { let (x, y) = (10 , 4 ); let op = Operations::Add; println! ("{:?}({:?}, {:?}) == {:?}" , op, x, y, op.run(x, y)); }
use 声明 屑 EnumName::KindName
就很长很麻烦,可以用 use 声明把枚举值的名字“导入”进来,然后就不用写前缀 EnumName::
了。
1 2 3 4 5 6 use WebEvent::{KeyPress, PageLoad}; use WebEvent::*; use Operations::*; inspect(KeyPress('e' )); inspect(PageLoad);
用 enum 撸链表 这个例子有意思,不是 C 那种结构体字段做指针,在操作节点时,判断指针字段为 null 时做基准情况单独处理。这个是把 Nil 作为枚举的一种情况,然后正常的节点用 Lisp 那种 cons 嵌套穿起来,操作时用 match 分别处理有值和末尾情况。
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #[derive(Debug)] enum List { Cons(u32 , Box <List>), Nil, } use List::*; impl List { fn new () -> List { Nil } fn prepend (self , elem: u32 ) -> List { Cons(elem, Box ::new(self )) } fn len (&self ) -> u32 { match *self { Cons(_, ref tail) => 1 + tail.len(), Nil => 0 , } } fn stringify (&self ) -> String { match *self { Cons(curr, ref tail) => { format! ("{}, {}" , curr, tail.stringify()) } Nil => { format! ("<Nil>" ) } } } } fn main () { let mut list = List::new(); list = list.prepend(1 ); list = list.prepend(2 ); list = list.prepend(3 ); println! ("list: {:?}, len={}" , list, list.len()); println! ("stringify: {}" , list.stringify()); }