Rust基本数据类型
1. 简介
在 Rust 中,每个值都属于某一个数据类型,用来告诉 Rust 它被指定为何种数据,以便明确数据处理方式。Rust 基本数据类型主要有两类子集:标量(scalar)和复合(compound)。
- 此文所讲的基本数据类型都是 Rust 原生的数据类型,它们都是创建在「栈」上的数据结构。
- Rust 标准库还提供了一些更复杂的数据类型,它们有些是创建在「堆」上的数据结构,比如下文提到的
vector
数据类型。
【注】Rust 是静态类型语言,因此在编译时就必须知道所有变量的类型。通常,根据值及其使用方式,Rust 编译器可以推断出我们想要用的类型;当多种类型均有可能时,必须增加类型注解,否则编译会报错。
2. 标量类型
标量(scalar)类型代表一个单独的值。Rust 有四种基本的标量类型:整型、浮点型、布尔类型和字符类型。
2.1 整型
Rust 内建的整数类型如下表所示:
长度 | 有符号 | 无符号 |
---|---|---|
8-bit | i8 |
u8 |
16-bit | i16 |
u16 |
32-bit | i32 |
u32 |
64-bit | i64 |
u64 |
128-bit | i128 |
u128 |
arch | isize |
usize |
其中,arch 长度依赖于运行程序的计算机架构:64 位架构上为 64-bit,32 位架构上为 32-bit。
Rust 中书写数字字面值的形式如下表所示:
数字字面值 | 举例 |
---|---|
Decimal(十进制) | 98_222 |
Hex(十六进制) | 0xff |
Octal(八进制) | 0o77 |
Binary(二进制) | 0b1111_0000 |
Byte(单字节字符) | b'A' |
其中,Byte 的书写形式仅限于 u8
类型,R_
为分隔符以方便读数。
【注】Rust 的默认整型为 i32
,它通常是最快的。
整型溢出
- 在 debug 模式下编译时,Rust 检查这类问题并使程序 panic,即表示程序因错误而退出。
- 在 release 模式下编译时,Rust 不检测溢出,而是会进行一种被称为二进制补码包装的操作(本质就是忽略溢出的位)。
2.2 浮点型
Rust 有两个原生的浮点数类型:f32
和 f64
,默认浮点数类型是 f64
。浮点数采用 IEEE-754 标准表示,法2
是单精度浮点数,f64
是双精度浮点数。
【注】在现代 CPU 中,f64
与 f32
速度几乎是一样的。
2.3 布尔类型
Rust 中的布尔类型用 bool
声明。和其他语言类似,它两种取值:true
和 false
。
2.4 字符类型
Rust 中的字符类型用 char
声明,它是 Rust 中最原生的字母类型。char
使用单引号指定,不同于字符串使用双引号指定。
- Rust 的
char
类型大小为四个字节,代表了一个 Unicode 标量值。 - 在 Rust 中,拼音字母、中文、日文、韩文等文字字符,甚至 emoji 和零长度的空白符都是有效的 char 值。
3. 复合类型
复合类型(compound)可以将多个值组合成一个类型,Rust 中原生的复合类型有:元组(tuple)、数组(array)、结构体(struct)。
3.1 元组
元组是一个将多个其他类型的值组合进一个复合类型的主要方式。元组长度固定,一旦声明,其长度不能改变。元组的声明语法如下:
1 |
|
tup
变量绑定到整个元组上,因为元组是一个单独的复合元素。为了从元组中获取单个值,可以使用模式匹配来「解构」元组值,或者直接使用 .
运算符按索引值(索引值从 0 开始)访问:
1 |
|
3.2 数组
另一个包含多个值的方式是数组,与元组不同,数组中的每个元素的类型必须相同。Rust 中的数组是固定长度的,一旦声明,其长度不能改变。数组的声明语法如下:
1 |
|
- 数组是一整块分配在栈上的内存,可以使用索引来访问数组的元素:
1 |
|
- 如果访问数组时索引溢出,在编译时可以通过,但在运行时会报错 panic 而退出。
【注】Rust 标准库中提供了 vector
集合类型,它可以实现数组长度的动态变化。
3.3 结构体
结构体和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。
- 定义结构的基本语法类似如下:
1 |
|
- 定义了结构体之后,可以通过为每个字段指定具体值来创建这个结构体的实例。
1 |
|
- 为了从结构体中获取某个特定的值,可以使用
.
运算符。 - 若想改变结构体实例中某个字段的值,则要求整个实例必须是可变的。Rust 并不允许只将某个字段标记为可变。
元组结构体
可以定义与元组类似的结构体,称为「元组结构体」。
- 元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型。定义元组结构体举例如下:
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);
- 不同元组结构体的实例是不相同的,不能相互替代,即使结构体中的字段有着相同的类型。
- 在其他方面,元组结构体实例类似于元组:可以将其解构为单独的部分,也可以使用
.
后跟索引来访问单独的值。自动引用和解引用
- 在 C/C++ 语言中,有两个不同的运算符来调用字段:
.
直接在对象上调用字段,而->
在一个对象的指针上调用字段,这时需要先解引用(dereference)指针。- Rust 并没有一个与
->
等效的运算符;相反,Rust 有一个叫「自动引用和解引用」(automatic referencing and dereferencing)的功能。
- 当
object
调用字段时,Rust 会自动为object
添加&
、&mut
或*
以便使object
与字段签名匹配。即object.field
和(&object).field
等价。
1
2
3
4
5
6
7
8
9
10
11
12
13
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let rect = Rectangle { width: 30, height: 50 };
println!(
"width: {}, height: {}",
rect.width,
(&rect).height
);
}
3.4 枚举
枚举(enumerations)允许通过列举可能的成员(variants)来定义一个类型。利用枚举列出可能的 IP 地址类型举例如下:
1 |
|
- 访问枚举中的成员使用
::
语法:IpAddrKind::V4
和IpAddrKind::V6
。 - 每个枚举成员都是定义的枚举类型,即
IpAddrKind::V4
和IpAddrKind::V6
都是IpAddrKind
类型。 - 枚举还能将数据直接和枚举的每一个成员绑定,这样就不需要额外定义结构体来关联枚举成员和对应数据。
1 |
|
- 枚举的每一个成员可以处理不同类型和数量的数据。枚举成员甚至可以包含另一个枚举。
1 |
|
Rust 标准库中常用枚举
- IpAddr 枚举:用来存储和编码 IP 地址。
1
2
3
4
enum IpAddr {
V4(Ipv4Addr),
V6(Ipv6Addr),
}
- Option 枚举:用来表示一个值要么有值要么没值。
1
2
3
4
enum Option<T> {
Some(T),
None,
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!