自定义类型 (Rust入门) 本文章参考自官方学习文档及社区学习文档以下是参考链接:
官方:
社区:
直接上手学习推荐:
概述点
结构体 结构体(structure,缩写成struct)有3种类型,使用struct
关键字来创建:
元组结构体(tuple struct),事实上就是具名元组而已
经典的C语言分割结构体(C struct)
单元结构体(unit struct),不带字段,在泛型中很有用
题目由通过例子学习Rust中文版(结构体)
增加一个计算长方形面积的函数 rect_area(尝试使用嵌套的解构方式)。
增加一个函数 square,接受的参数是一个 Point 和一个 f32,并返回一个 Rectangle(长方形)的信息,包括左下角的点,以及长和宽的浮点数值。
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 #[derive(Debug)] struct Person <'a > { name: &'a str , age: u8 , } struct Nil ;struct Pair (i32 , f32 );#[derive(Debug)] struct Point { x: f32 , y: f32 , } #[derive(Debug)] struct Rectangle { p1: Point, p2: Point, } fn rect_area (r: Rectangle) -> f32 { let Rectangle { p1: Point{x:top,y:left}, p2: Point{x:bottom,y:right}, } = r; (top-bottom)*(right-left) } fn square (_p:Point, f: f32 ) -> Rectangle { let rect = Rectangle { p1: Point{x: _p.x, y: _p.y }, p2: Point{x: _p.x-f, y: _p.y+f }, }; rect } fn main () { let name = "Peter" ; let age = 27 ; let peter = Person { name, age }; println! ("{:?}" , peter); let point : Point = Point { x: 12.2 , y: 23.4 }; println! ("point coordinates: ({}, {})" , point.x, point.y); let new_point = Point { x: 0.1 , ..point }; println! ("second point: ({}, {})" , new_point.x, new_point.y); let Point { x: my_x, y: my_y } = point; let _rectangle = Rectangle { p1: Point { x: my_y, y: my_x }, p2: point, }; let _nil = Nil; let pair = Pair (1 , 0.1 ); println! ("pair contains {:?} and {:?}" , pair.0 , pair.1 ); let Pair (integer, decimal) = pair; println! ("pair contains {:?} and {:?}" , integer, decimal); println! ("rect_area {:.2}" , rect_area (_rectangle)); println! ("square: {:?}" , square (Point{x: 1.0 , y: 2.0 }, 3.2 )); }
枚举 enum
关键字允许创建一个代表数个可能变量的数据的类型(原文:The enum keyword allows the creation of a type which may be one of a few different variants.
若您对此句有 更好的翻译或理解,希望指出来,谢谢。)。在 struct
中任何合法的变量在 enum
同样是合法的。
示例出自蓝桥云课 原实验楼
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 #![allow(dead_code)] enum WebEvent { PageLoad, PageUnload, KeyPress (char ), Paste (String ), Click { x: i64 , y: i64 } } fn inspect (event: WebEvent) { match event { WebEvent::PageLoad => println! ("page loaded" ), WebEvent::PageUnload => println! ("page unloaded" ), WebEvent::KeyPress (c) => println! ("pressed '{}'." , c), WebEvent::Paste (s) => println! ("pasted \"{}\"." , s), WebEvent::Click { x, y } => { println! ("clicked at x={}, y={}." , x, y); }, } } fn main () { let pressed = WebEvent::KeyPress ('x' ); let pasted = WebEvent::Paste ("my text" .to_owned ()); let click = WebEvent::Click { x: 20 , y: 80 }; let load = WebEvent::PageLoad; let unload = WebEvent::PageUnload; inspect (pressed); inspect (pasted); inspect (click); inspect (load); inspect (unload); }
执行结果:
1 2 3 4 5 pressed 'x' . pasted "my text" . clicked at x=20, y=80. page loaded page unloaded
类型别名 若使用类型别名,则可以通过其别名引用每个枚举变量。当枚举的名称太长或者太一般化,且你想要对其重命名,那么这对你会有所帮助。
1 2 3 4 5 6 7 8 9 10 11 12 13 enum VeryVerboseEnumOfThingsToDoWithNumbers { Add, Subtract, } type Operations = VeryVerboseEnumOfThingsToDoWithNumbers;fn main () { let x = Operations::Add; }
最常见的情况就是在 impl 块中使用 Self 别名。
1 2 3 4 5 6 7 8 9 10 11 12 13 enum VeryVerboseEnumOfThingsToDoWithNumbers { Add, Subtract, } impl VeryVerboseEnumOfThingsToDoWithNumbers { fn run (&self , x: i32 , y: i32 ) -> i32 { match self { Self ::Add => x + y, Self ::Subtract => x - y, } } }
该功能已在 Rust 中稳定化,可以阅读 [stabilization report][aliasreport]
来了解更多有关枚举和类型别名的知识。
使用 use 使用 use 声明的话,就可以不写出名称的完整路径了:
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 #![allow(dead_code)] enum Status { Rich, Poor, } enum Work { Civilian, Soldier, } fn main () { use Status::{Poor, Rich}; use Work::*; let status = Poor; let work = Civilian; match status { Rich => println! ("The rich have lots of money!" ), Poor => println! ("The poor have no money..." ), } match work { Civilian => println! ("Civilians work!" ), Soldier => println! ("Soldiers fight!" ), } }
C语言风格用法 enum
也可以像C语言
风格的枚举类型那样使用
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 #![allow(dead_code)] enum Number { Zero, One, Two, } enum Color { Red = 0xff0000 , Green = 0x00ff00 , Blue = 0x0000ff , } fn main () { println! ("zero is {}" , Number::Zero as i32 ); println! ("one is {}" , Number::One as i32 ); println! ("roses are #{:06x}" , Color::Red as i32 ); println! ("violets are #{:06x}" , Color::Blue as i32 ); }
测试实例:链表 enum
的常见一个用法就是创建链表
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 use List::*;enum List { Cons (u32 , Box <List>), Nil, } 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 (head, ref tail) => { format! ("{}, {}" , head, 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! ("linked list has length: {}" , list.len ()); println! ("{}" , list.stringify ()); }
注:ref
关键字可用来创建结构体/元组的字段引用,下面示例使用的是模式匹配,它还可以用于解构
原文注解:
https://doc.rust-lang.org/std/keyword.ref.html
原文 Bind by reference during pattern matching.ref
annotates pattern bindings to make them borrow rather than move. It is not a part of the pattern as far as matching is concerned: it does not affect whether a value is matched, only how it is matched.
中文 在模式匹配期间通过引用绑定。ref
批注模式绑定以使其借用而不是移动。就匹配而言,它不是模式的一部分:它不会影响值是否匹配,只影响匹配方式。
&
与ref
常量 Rust 有两种常量,可以在任意作用域声明,包括全局作用域。它们都需要显式的类型声明:
const
:不可改变的值(通常使用这种)
static
:具有static
生命周期的,可以是可变的变量(译注:须使用 static mut
关键字)。
有个特例就是 “string” 字面量。它可以不经改动就被赋给一个 static 变量,因为它的类型标记:&’static str 就包含了所要求的生命周期 ‘static。其他的引用类型都必须特地声明,使之拥有 ‘static 生命周期。这两种引用类型的差异似乎也无关紧要,因为无论如何,static 变量都得显式地声明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 static LANGUAGE: &'static str = "Rust" ;const THRESHOLD: i32 = 10 ;fn is_big (n: i32 ) -> bool { n > THRESHOLD } fn main () { let n = 16 ; println! ("This is {}" , LANGUAGE); println! ("The threshold is {}" , THRESHOLD); println! ("{} is {}" , n, if is_big (n) { "big" } else { "small" }); }