切片类型
切片(Slice)是对数据值的部分“引用”
我们可以从一个数据集合中取一部分来使用
字符串切片
例如
1 2 3 4 5 6 7 8
| fn main() { let s = String::from("broadcast");
let part1 = &s[0..5]; let part2 = &s[5..9];
println!("{}={}+{}", s, part1, part2); }
|
这里的0..5
是前闭后开区间实际上内存上是这样的

有一些简便的写法,可以这样写
1 2 3
| ..y 等价于 0..y x.. 等价于位置 x 到数据结束 .. 等价于位置 0 到结束
|
被切片引用的字符串是不允许被修改的,除此之外,我们需要区分str
和String
这两个字符串类型
前者指的是堆内存中的字符串,我们可以理解为常量字符串,用的时候是作为&str
引用使用的
String
实际上是一种数据类型,类似于C++中的string
类,有追加,清空等一系列操作
这两者都支持切片,切片的结果必须是引用类型
其他结构的切片
1 2 3 4 5 6 7
| fn main() { let arr = [1, 3, 5, 7, 9]; let part = &arr[0..3]; for i in part.iter() { println!("{}", i); } }
|
原理都是类似的
结构体
结构体和元组是类似的,可以将不同类型的数据作为一个整体,但是结构体内部每个成员是有名字的
例如
1 2 3 4 5 6
| struct Site { domain: String, name: String, nation: String, found: u32 }
|
这里的结构体和C++中的不太一样,这里的结构体只能用来定义类型,不能实例化对象,不需要;
,成员用,
分割
结构体实例
结构体实例化是使用key: value
的形式进行赋值的,例如
1 2 3 4 5 6
| let baidu = Site { domain: String::from("www.baidu.com"), name: String::from("baidu"), nation: String::from("China"), found: 2013 };
|
如果当前作用域有和成员变量名称相同的,可以直接写
1 2 3 4 5 6 7 8
| let domain = String::from("www.baidu.com"); let name = String::from("baidu"); let baidu = Site { domain, name, nation: String::from("China"), traffic: 2013 };
|
如果用一个结构体实例的一部分去构建另一个结构体,可以这样写
1 2 3 4 5
| let site = Site { domain: String::from("www.baidu.com"), name: String::from("b"), ..baidu };
|
但是不允许全部用旧结构体的
元组结构体
元组结构体的定义和使用更为简单,实际上是一种元组形式的结构体,区别就是有名字和固定的类型格式,主要是为了处理定义经常使用的简单类型用的
1 2 3 4 5
| struct Color(u8, u8, u8); struct Point(f64, f64);
let black = Color(0, 0, 0); let origin = Point(0.0, 0.0);
|
使用方法就和普通的元组使用是一样的了
结构体所有权
结构体实例会掌握所有成员的所有权,因为当结构体生命周期结束的时候,会释放所有字段
输出结构体
1 2 3 4 5 6 7 8 9 10 11
| #[derive(Debug)] struct Rectangle { width: u32, height: u32, }
fn main() { let rect1 = Rectangle { width: 30, height: 50 };
println!("rect1 is {:?}", rect1); }
|
第一行是调用调试库,然后用:?
做占位符就可以输出整个结构体的内容了,使用:#?
就可以自动格式化
结构体的方法
结构体的方法主要是用于操作结构体实例本身的
Rust语言其实不是面向对象的,但是也可以实现面向对象的思想
结构体方法的第一个参数必须是&self
,不需要声明类型
例如计算一个矩形的面积
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| struct Rectangle { width: u32, height: u32, } impl Rectangle { fn area(&self) -> u32 { self.width * self.height } }
fn main() { let rect1 = Rectangle { width: 30, height: 50 }; println!("rect1's area is {}", rect1.area()); }
|
调用结构体方法的时候就可以不用写self了
结构体关联函数
如果做impl中,但是没有&self
参数,而是属于结构体全体的,不属于某个具体的实例
类似于C++中的静态成员函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #[derive(Debug)] struct Rectangle { width: u32, height: u32, }
impl Rectangle { fn create(width: u32, height: u32) -> Rectangle { Rectangle { width, height } } }
fn main() { let rect = Rectangle::create(30, 50); println!("{:?}", rect); }
|
单元结构体
结构体也可以不需要任何成员
枚举
Rust的枚举和C++的枚举还是不太一样的,但是使用是比较简单的,例如
1 2 3 4 5 6 7 8 9 10
| #[derive(Debug)]
enum Book { Papery, Electronic }
fn main() { let book = Book::Papery; println!("{:?}", book); }
|
我们可以给枚举添加元组属性描述,或者使用结构体的语法都是可以的
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| enum Book { Papery(u32), Electronic(String), }
let book = Book::Papery(1001); let ebook = Book::Electronic(String::from("url://..."));
enum Book { Papery { index: u32 }, Electronic { url: String }, } let book = Book::Papery{index: 1001};
|
但是我们无法访问具体枚举对应的值是什么,访问的方法在下面介绍
match语法
match很类似switch,但是rust并不支持switch
例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| fn main() { enum Book { Papery {index: u32}, Electronic {url: String}, } let book = Book::Papery{index: 1001}; let ebook = Book::Electronic{url: String::from("url...")}; match book { Book::Papery { index } => { println!("Papery book {}", index); }, Book::Electronic { url } => { println!("E-book {}", url); } } }
|
基本格式是这样的
1 2 3 4 5
| match 枚举类实例 { 分类1 => 返回值表达式, 分类2 => 返回值表达式, ... }
|
但是所有返回值表达式的类型必须是一样的
match除了可以处理枚举,也可以处理整数、浮点数、字符、字符串切片引用的,但是不推荐使用浮点数,有可能有精度问题
默认情况用_
表示,例如
1 2 3 4 5 6 7
| fn main() { let t = "abc"; match t { "abc" => println!("Yes"), _ => {}, } }
|
Option枚举类
Option时Rust标准库自带的枚举类,这主要是为了解决Rust没有空引用的问题
Option具体是这样的
1 2 3 4
| enum Option<T> { Some(T), None, }
|
我们如果要对这个类型的数据做操作的时候,就必须先判断是否时None
1 2 3 4 5 6 7 8 9 10 11
| fn main() { let opt = Option::Some("Hello"); match opt { Option::Some(something) => { println!("{}", something); }, Option::None => { println!("opt is nothing"); } } }
|
如果我们想要声明某个变量是空值时,就必须先声明明确的类型
1 2 3 4 5 6 7 8 9 10 11
| fn main() { let opt: Option<&str> = Option::None; match opt { Option::Some(something) => { println!("{}", something); }, Option::None => { println!("opt is nothing"); } } }
|
Option是默认引入的,所以可以直接写Some()
或者None
if let 语句
这是一种match语句的语法糖,可以用来简化匹配match枚举类型的yufa
如果直接使用if else
1 2 3 4 5 6
| let maybe_name = Some("Alice");
if maybe_name { println!("Name is: {}", maybe_name); }
|
正确的方式是使用if let ,当然这个后面可以加上else
1 2 3 4 5 6
| let maybe_name = Some("Alice");
if let Some(name) = maybe_name { println!("Name is: {}", name); }
|
对应的match写法是
1 2 3 4 5
| match maybe_name { Some(name) => println!("Name is: {}", name), _ => (), }
|