Rust 自定义类型

  |   0 评论   |   0 浏览

Rust 自定义类型主要有两种:结构体和枚举类型。

结构体

和元组一样,结构体中的值可以是不同的数据类型,但结构体有自己的名称,并且需定义结构体中各个数据的名称和类型,称之为字段(field)。

结构体分为三类:

  • C 语言风格结构体(C struct)
  • 元组结构体(uple struct)
  • 单元结构体(unit-like struct)

C 语言风格结构体

示例: 结构体的定义和实例化

 1// 定义 User 结构体
 2// 使用 `struct` 关键字,指定结构体名称,在大括号内指定字段(field)名和字段类型
 3struct User {
 4    username: String,
 5    email: String,
 6    sign_in_count: u64,
 7    active: bool,
 8}
 9// 创建一个 User 结构体的实例
10let user1 = User {
11    email: String::from("someone@example.com"),
12    username: String::from("someusername123"),
13    active: true,
14    sign_in_count: 1,
15};
16// 修改字段的值
17user1.email = String::from("anotheremail@example.com");
18
19// 使用更新语法(struct update syntax)利用现有实例创建新的实例
20let user2 = User {
21    email: String::from("another@example.com"),
22    username: String::from("anotherusername567"),
23    ..user1 // 剩余字段与 user1 相同
24};

元组结构体

元组结构体(tuple struct)是一种没有字段名的特殊结构体。

示例 :定义元组结构体

1struct Color(i32, i32, i32);
2struct Point(i32, i32, i32);
3
4let black = Color(0, 0, 0);
5let origin = Point(0, 0, 0);

单元结构体

单元结构体不包含任何字段,它的实例不存放数据。

示例:定义一个单元结构体

1struct Nil

定义方法

方法与函数类似:它们使用 fn 关键字和名称声明,可以拥有参数和返回值。方法和结构体关联,并且它的第一个参数通常是selfself指调用该方法的结构体实例)。

示例:定义结构体Rectanglearea方法

 1#[derive(Debug)]
 2struct Rectangle {
 3    width: u32,
 4    height: u32,
 5}
 6
 7impl Rectangle {
 8    fn area(&self) -> u32 {
 9        self.width * self.height
10    }
11}
12
13fn main() {
14    let rect1 = Rectangle { width: 30, height: 50 };
15
16    println!(
17        "The area of the rectangle is {} square pixels.",
18        rect1.area() // 调用area方法
19    );
20}

关联函数

可以在 impl 块中定义不以 self 作为参数的函数。这被称为关联函数(associated functions),因为它们与结构体相关联。

关联函数经常被用作返回一个结构体新实例的构造函数。比如:String::from就是一个关联函数。

示例:定义结构体Rectangle的关联函数square

1// 定义一个关联函数
2impl Rectangle {
3    fn square(size: u32) -> Rectangle {
4        Rectangle { width: size, height: size }
5    }
6}
7// 调用关联函数
8let sq = Rectangle::square(3);

枚举类型

Rust 中的枚举类型与 C 语言中的类似,但功能更强大。

定义枚举类型

使用enum关键字定义枚举类型。

 1// 定义一个描述IP类型的枚举类型
 2enum IpAddrKind {
 3    V4,
 4    V6,
 5}
 6
 7// 定义一个描述IP地址的枚举类型
 8enum IpAddr {
 9    V4(u8, u8, u8, u8), // 枚举的成员也可以是结构体
10    V6(String),
11}
12
13// 定义一个描述网络事件的枚举
14enum WebEvent {
15    // 单元结构体
16    PageLoad,
17    PageUnload,
18    // 元组结构体
19    KeyPress(char),
20    Paste(String),
21    // 普通的结构体
22    Click { x: i64, y: i64 }
23}

使用枚举

通常可以使用::符号访问枚举成员。

示例

 1enum SpecialPoint {
 2    Point(i32, i32),
 3    Special(String),
 4}
 5fn main() {
 6    let sp = SpecialPoint::Point(0, 0);
 7    match sp {
 8        SpecialPoint::Point(x, y) => {
 9            println!("I'm SpecialPoint(x={}, y={})", x, y);
10        }
11        SpecialPoint::Special(why) => {
12            println!("I'm Special because I am {}", why);
13        }
14    }
15}

使用use声明后,可以直接使用枚举的成员。
示例

 1enum Status {
 2    Rich,
 3    Poor,
 4}
 5
 6fn main() {
 7    use Status::{Poor, Rich};
 8    // use Status::*; // 也可以使用这种方式
 9
10    // `Poor` 等价于 `Status::Poor`。
11    let status = Poor;
12
13    match status {
14        Rich => println!("The rich have lots of money!"),
15        Poor => println!("The poor have no money..."),
16    }
17}

定义方法

与结构体一样,可以在impl块中给枚举类型定义方法。

示例

 1enum Operations {
 2    Add,
 3    Subtract,
 4}
 5
 6impl Operations {
 7    fn run(&self, x: i32, y: i32) -> i32 {
 8        match self {
 9            Self::Add => x + y,
10            Self::Subtract => x - y,
11        }
12    }
13}

Option<T>

许多其他语言都有的空值功能。空值(Null)是一个值,它代表没有值。在这些语言中,一个变量要么是一个空值,要么是一个非空值。但这样的设计很容易引发错误,比如 Java 中常见的空指针异常(NullPointerException),通常是开发者忘记了处理变量值为 Null 的情况,并且编译器无法检查出来。

Tony Hoare,Null 的发明者,在他 2009 年的演讲 “Null References: The Billion Dollar Mistake” 中也曾经说到:

I call it my billion-dollar mistake. At that time, I was designing the first comprehensive type system for references in an object-oriented language. My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

Rust 没有空值,它采用了另一种方式来表示有值还是没有值。它在标准库定义了一个枚举类型:Option<T>。其定义如下:

1enum Option<T> {
2    Some(T),
3    None,
4}

Option<T> 是预加载的,可以不需要 Option:: 前缀来直接使用 SomeNoneSome 成员可以包含任意类型的数据,None 表示空值。

当在使用 Option<T> 类型时,编译器就会知道可能会有 None,它会检查代码中有没有对 None 进行处理。并且 Option<T>T(即:Option包含的类型,它可以是任何类型)是不同的类型,必须将 Option<T> 拆箱之后才能和 T 类型值进行运算,这也间接的提醒开发者必须对 None 进行处理。

相关资料

Rust Programming Language

Rust By Example

RustPrimer