Rust - Slice, Struct, Enum
Slice
字符串切片
- 字符串切片: 指向字符串中一部分内容的引用
- 形式:
[开始索引..结束索引]
- 开始索引: 切片起始位置的索引值
- 结束索引: 切片终止位置的下一个索引值
- 字符串切片的范围索引必须发生在有效的 UTF-8 字符边界内
- 如果尝试从一个多字节的字符中创建字符串切片,程序会报错并退出
1
2
3
4
5
| let s = String::from("hello world");
let hello = &s[0..5]; // 也可以写成 &s[..5]
let world = &s[6..11]; // 也可以写成 &s[6..]
let hello_world = &s[0..11]; // 也可以写成 &s[0..s.len()] &s[..]
|
- 字符串字面值
&str
是切片
- 其是被直接存储在二进制程序中的
&str
是不可变引用,所以字符串字面值也是不可变的
1
2
| let s = "hello world"; // &str 字符串切片类型
// s 是指向二进制程序特定位置的切片
|
其他类型的切片
1
2
| let a = [1, 2, 3, 4, 5];
let slice = &a[1..3]; // 类型为 &[i32]
|
Struct
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| // struct 又自身所有数据的所有权,只要 struct 实例是有效的,那么里面的字段数据也是有效的
// struct 里面的字段也可以放引用,但是需要使用生命周期 (生命周期可以保证只要 struct 实例有效,那么里面的引用也是有效的)
struct User {
username: String, // 持有所有权
email: String, // 持有所有权
age: i32, // 标量类型
}
// 一旦 struct 的实例是可变的,那么实例中所有的字段都是可变的
let mut user = User {
email: String::from("a@qq.com"),
username: String::from("wt"),
age: 16,
};
println!("{}", user.email);
user.email = String::from("b@qq.com");
// 字段名与变量名相同使,可初始化简写
fn build_user(email: String, username: String) -> User {
User { email, username, age: 16 }
}
// 基于某个 struct 实例,创建新的 struct
let user2 = User { email: String::from("c@qq.com"), ..user1 };
|
1
2
3
4
5
6
7
8
9
10
11
12
| struct Point3d {
x: i32,
y: i32,
z: i32,
}
fn default() -> Point3d {
Point3d { x: 0, y: 0, z: 0 }
}
let origin = Point3d { x: 5, ..default() };
let point = Point3d { z: 1, x: 2, ..origin };
|
Tuple Struct
1
2
3
4
5
| struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
// Color, Point 是不同的类型
|
1
2
3
4
5
6
7
8
9
10
11
| // 常用于包装一些基本数据类型,去扩展它的功能 (NewType 模式)
struct Score(u32);
impl Score {
fn pass(&self) -> bool {
self.0 >= 60
}
}
let s = Score(59);
assert_eq!(s.pass(), false);
|
Unit-Like Struct
- 适用于需要在某个类型上实现某个 trait,但是在里面又没有想要存储的数据
- 可以看作是占位类型,其实例就是其自身。不管创建多少实例,编译器都会优化成同一个,其也不会占用内存空间,是一个零大小类型
1
2
3
4
| struct Unit;
let unit1 = Unit;
let unit2 = Unit;
|
Recursive Enum
1
2
3
4
| struct Recursive {
Data: i32,
rec: Box<Recursive>, // 需要用 Box 包装
}
|
Print Struct
1
2
3
4
5
6
7
8
9
| #[derive(Debug)]
struct User {
a: u32,
b: u32,
}
let u = User { a: 1, b: 2 };
println!("{:?}", u);
println!("{:#?}", u); // 比 {:?} 更漂亮些
|
Struct Method
- C/C++ 调用方法:
obj->something()
和 (*obj).something()
- Rust 没有
->
运算符, Rust 会自动引用或者解引用
- 在调用方法时,Rust 根据情况会自动添加
&
、&mut
、或 *
,以便 Object 可以匹配方法的签名
p1.distance(&p2)
效果等价于 (&p1).distance(&p2)
- 每个 struct 可以有多个 impl 块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| struct User {
username: String,
email: String,
}
impl User {
// 实例方法
fn say(&self, st: &str) {
println!("{} say: {}", self.username, st);
}
// 静态方法 (关联函数)
fn dosomething() {}
}
fn main() {
let u = User { username: "wt".to_string(), email: "a@a.com".to_string() };
u.say("hello"); // wt say: hello
// 调用关联函数
User::dosomething();
}
|
Enum
1
2
3
4
5
6
7
8
9
10
11
12
13
| enum IpAddrKind {
V4,
V6,
}
fn main() {
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
route(four);
}
fn route(ip_kind: IpAddrKind) {}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| // 数据附加到枚举到变体中
// - 优点:
// - 不需要额外使用 struct 存储数据
// - 每个变体可以拥有不同的类型以及关联的数据
enum IpAddrKind {
V4(u8, u8, u8, u8), // 可嵌入任意类型的数据,String、struct ...
V6(String),
}
fn main() {
let home = IpAddrKind::V4(127, 0, 0, 1);
let loopback = IpAddrKind::V6(String::from("::1"));
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| enum Message {
Quite,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
// enum method
impl Message {
fn call(&self) {}
}
fn main() {
let q = Message::Quit;
let m = Message::Move { x: 12, y: 24 };
let w = Message::Write(String::from("Hello"));
let c = Message::ChangeColor(0, 255, 255);
c.call();
}
|
Option Enum
- 定义于标准库中,在 Prelude(预导入模块)中
- 描述了: 某个值可能存在(某种类型)或不存在的情况
- Rust 没有 Null,有类似 Null 概念的枚举
Option<T>
- 其包含在 Prelude 中可以直接使用
Option<T>
、Some<T>
、None
1
2
3
4
5
| // 标准库中的定义
enum Option<T> {
Some(T),
None,
}
|
1
2
3
4
| let some_num = Some(5);
let some_str = Some("a");
let absent_num: Option<i32> = None;
|
Union
1
2
3
4
| union U {
u: u32,
v: u64,
}
|