3 用户自定义类型
Rust自定义类型主要通过下面两个关键进行定义:
- struct:定义一个结构
- enum:定义一个枚举
常量能以通过const和static关键字创建。
3.1 结构
有三种类型的结构(“structs”),可以使用struct关键字来创建:
- 元组结构体,又名元组
- 传统C结构体
- 元结构体,无field,为了做成通用类型
// A unit struct struct Nil; // A tuple struct struct Pair(i32, f64); // A struct with two fields struct Point { x: f64, y: f64, } // Structs can be reused as fields of another struct #[allow(dead_code)] struct Rectangle { p1: Point, p2: Point, } fn main() { // Instantiate a `Point` let point: Point = Point { x: 0.3, y: 0.4 }; // Access the fields of the point println!("point coordinates: ({}, {})", point.x, point.y); // Destructure the point using a `let` binding let Point { x: my_x, y: my_y } = point; let _rectangle = Rectangle { // struct instantiation is an expression too p1: Point { x: my_y, y: my_x }, p2: point, }; // Instantiate a unit struct let _nil = Nil; // Instantiate a tuple struct let pair = Pair(1, 0.1); // Destructure a tuple struct let Pair(integer, decimal) = pair; println!("pair contains {:?} and {:?}", integer, decimal); }
程序执行结果:
point coordinates: (0.3, 0.4) pair contains 1 and 0.1
3.2 枚举
enum关键字允许创建一个可能有许多变体的变量。每一个对结构体来说是合法的变体,对枚举同样是合法的。
// An attribute to hide warnings for unused code. #![allow(dead_code)] // Create an `enum` to classify someone. Note how both names // and type information together specify the variant: // `Skinny != Fat` and `Height(i32) != Weight(i32)`. Each // is different and independent. enum Person { // An `enum` may either be `unit-like`, Skinny, Fat, // like tuple structs, Height(i32), Weight(i32), // or like structures. Info { name: String, height: i32 } } // A function which takes a `Person` enum as an argument and // returns nothing. fn inspect(p: Person) { // Usage of an `enum` must cover all cases (irrefutable) // so a `match` is used to branch over it. match p { Person::Skinny => println!("Is skinny!"), Person::Fat => println!("Is fat!"), // Destructure `i` from inside the `enum`. Person::Height(i) => println!("Has a height of {}.", i), Person::Weight(i) => println!("Has a weight of {}.", i), // Destructure `Info` into `name` and `height`. Person::Info { name, height } => { println!("{} is {} tall!", name, height); }, } } fn main() { let person = Person::Height(18); let danny = Person::Weight(10); // `to_owned()` creates an owned `String` from a string slice. let dave = Person::Info { name: "Dave".to_owned(), height: 72 }; let john = Person::Fat; let larry = Person::Skinny; inspect(person); inspect(danny); inspect(dave); inspect(john); inspect(larry); }
程序运行结果:
Has a height of 18. Has a weight of 10. Dave is 72 tall! Is fat! Is skinny!
3.2.1 use
可以使用use声明,所以不用手动指定作用域:
// An attribute to hide warnings for unused code. #![allow(dead_code)] enum Status { Rich, Poor, } enum Work { Civilian, Soldier, } fn main() { // Explicitly `use` each name so they are available without // manual scoping. use Status::{Poor, Rich}; // Automatically `use` each name inside `Work`. use Work::*; // Equivalent to `Status::Poor`. let status = Poor; // Equivalent to `Work::Civilian`. let work = Civilian; match status { // Note the lack of scoping because of the explicit `use` above. Rich => println!("The rich have lots of money!"), Poor => println!("The poor have no money..."), } match work { // Note again the lack of scoping. Civilian => println!("Civilians work!"), Soldier => println!("Soldiers fight!"), } }
程序执行结果:
The poor have no money... Civilians work!
3.2.2 C-like
enum也能像C预言的枚举那样使用。
// An attribute to hide warnings for unused code. #![allow(dead_code)] // enum with implicit discriminator (starts at 0) enum Number { Zero, One, Two, } // enum with explicit discriminator enum Color { Red = 0xff0000, Green = 0x00ff00, Blue = 0x0000ff, } fn main() { // `enums` can be cast as integers. 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); }
程序运行结果为:
zero is 0 one is 1 roses are #ff0000 violets are #0000ff
3.2.3 测试用例:链表
enums一个普通的使用时创建链表:
use List::*; enum List { // Cons: Tuple struct that wraps an element and a pointer to the next node Cons(u32, Box<List>), // Nil: A node that signifies the end of the linked list Nil, } // Methods can be attached to an enum impl List { // Create an empty list fn new() -> List { // `Nil` has type `List` Nil } // Consume a list, and return the same list with a new element at its front fn prepend(self, elem: u32) -> List { // `Cons` also has type List Cons(elem, Box::new(self)) } // Return the length of the list fn len(&self) -> u32 { // `self` has to be matched, because the behavior of this method // depends on the variant of `self` // `self` has type `&List`, and `*self` has type `List`, matching on a // concrete type `T` is preferred over a match on a reference `&T` match *self { // Can't take ownership of the tail, because `self` is borrowed; // instead take a reference to the tail Cons(_, ref tail) => 1 + tail.len(), // Base Case: An empty list has zero length Nil => 0 } } // Return representation of the list as a (heap allocated) string fn stringify(&self) -> String { match *self { Cons(head, ref tail) => { // `format!` is similar to `print!`, but returns a heap // allocated string instead of printing to the console format!("{}, {}", head, tail.stringify()) }, Nil => { format!("Nil") }, } } } fn main() { // Create an empty linked list let mut list = List::new(); // Append some elements list = list.prepend(1); list = list.prepend(2); list = list.prepend(3); // Show the final state of the list println!("linked list has length: {}", list.len()); println!("{}", list.stringify()); }
程序运行结果:
linked list has length: 3 3, 2, 1, Nil
3.3 常量
Rust有两种不同类型的常量,这些常量可以在任何作用于定义,包括全局。两种方法都需要显示声明:
- const:一个不可改变的值(通常用法)
- static:一个可能在staic声明周期内可变的变量
“string”是一个特例。它可以直接赋值给一个static变量,而不需要修改,因为它的类型签名:&‘static str已经使用了‘static生命周期。所有其他的引用类型必须使用‘static声明走起做特殊注解。
// Globals are declared outside all other scopes. static LANGUAGE: &'static str = "Rust"; const THRESHOLD: i32 = 10; fn is_big(n: i32) -> bool { // Access constant in some function n > THRESHOLD } fn main() { let n = 16; // Access constant in the main thread println!("This is {}", LANGUAGE); println!("The threshold is {}", THRESHOLD); println!("{} is {}", n, if is_big(n) { "big" } else { "small" }); // Error! Cannot modify a `const`. //THRESHOLD = 5; // FIXME ^ Comment out this line }
程序运行结果:
This is Rust The threshold is 10 16 is big
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-13 10:33:27