Rust数据类型
简介
Rust 的数据类型分为 基本类型(scalar标量)、特殊基本类型、复合类型(compound)和 集合类型4 种:
| 类型写法 | 描述 | 值举例 |
|---|---|---|
i8, i16, i32, i64,<br>u8, u16, u32, u64 | i:带符号 <br>u:无符号 <br>数字代表存储位数 | 42,<br>-5i8, 0x400u16, 0o100i16,<br>20_922_789_888_000u64,<br>b'*' (u8 byte literal) |
| isize, usize | 带符号/无符号 整型 <br>存储位数与系统位数相同 <br>(32 或 64 位整数) | 137,<br>-0b0101_0010isize,<br>0xffff_fc00usize |
| f32, f64 | IEEE 标准的浮点数,单精度/双精度 | 1.61803, 3.14f32,<br>6.0221e23f64 |
| bool | 布尔型 | true, false |
| char | Unicode 字符 <br>存储空间固定为 4 字符 | ‘*’, ‘\n’, ‘字’, ‘\x7f’, ‘\u{CA0}’ |
| (char, u8, i32) | 元组 tuple:可以存储多种类型 | ('%', 0x7f, -1) |
| () | 单元类型,实际上是空 tuple | () |
| struct S{x: f32, y: f32 } | 命名元素结构体,数据成员有变量名的结构体 | struct S { x: 120.0, y: 209.0 } |
| struct T(i32, char) | 元组结构体,数据成员无名称,形如元组,不可与元组混淆 | struct T(120, ‘X’) |
| struct E | 单元型结构体,没有数据成员 | E |
enum Attend {<br>OnTime, Late(u32)<br>} | 枚举类型,枚举类型默认没有比较是否相等的运算,更没有比较大小 | Attend::Late(5),<br>Attend::OnTime |
Box <Attend> | Box 指针类型,指向堆内存中的一个泛型值 | Box::new(Late(15)) |
| &i32, &mut i32 | 只读引用和可变引用,物所有权,生命周期不能超过所指向的值。<br>只读引用也叫共享引用, | &s.y, &mut v |
| String | 字符串,UTF-8 格式存储,长度可变 | “编程”.to_string()<br>to_string 函数返回一个字符串类型 |
| &str | str 的引用,指向 UTF-8 文本的指针,无所有权 | “そば: soba”, &s[0..12] |
| [f64; 4], [u8; 256] | 数组,固定长度,内部数据类型必须一致 | [1.0, 0.0, 0.0, 1.0],<br>[b' ‘; 256] |
Vec <f64> | Vector 向量,可变长度,内部数据类型必须一致 | vec![0.367, 2.718, 7.389] |
&[u8..u8],<br>&mut [u8..u8] | 切片引用,通过起始索引和长度指向数组或向量的一部分连续元素 | &v[10..20], &mut a[..] |
| &Any, &mut Read | traid 对象:实现了某 trait 内方法的对象 <br>示例中 Any、Read 都是 trait | value as &Any,<br>&mut file as &mut Read |
fn(&str, usize) -><br>isize | 函数类型,可以理解为函数指针 | i32::saturating_add |
| 闭包 | 闭包 | |a, b| aa + bb |
上表中没有 byte 类型,是因为 Rust 压根就没有 byte 类型,实际上等于 u8,在一般计算中认为是 u8,
在文件或网络中读写数据时经常称为 byte 流。
基本类型(scalar)
标量类型表示一个单独的值,包括:
- 布尔类型(bool)
- 数值(numeir)
- 字符 (char)
布尔类型(bool)
- bool 类型占一个 byte, 从而允许指针指向其地址;
- bool 型取值:
true,false; as运算符可以将 bool 值转换为整数类型,false -> 0,true 转换为 1;as不会从数值类型转换为 bool
| |
数值类型(numeric)
- 不允许隐式转换;
- 如果需要调用类型的方法, 在有二意的情况下必须显式转换, 例如加后缀:
(2.0_f64).sqrt(); bool,char,enum可以转换为任意整型integer, 但反向转换不行, 唯一例外是u8转char;- 有符号整形:
i8, i16, i32, i64; - 无符号整形:
u8, u16, u32, u64; - 带符号/无符号整型, 存储位数与系统位数相同:
isize, usize; - 单/双精度浮点型:
f32, f64; - 带符号整型,使用最高一位(bit)表示为符号,0 为正数,1 为负数,其他位是数值,用补码表示;
- Rust 要求数组的索引必须是 usize 类型,在一些数据结构中,数组和向量的元素数也是 usize 型;
- 数值类型可以通过
as运算符进行转换; as运算符在转换时,对存储的数字并不改动,只是把数读出来的时候进行截取、扩展、或决定是否采用补码翻译;- f32 和 f64 类型都定义了一些特殊值常量: INFINITY(无穷大)、 NEG_INFINITY (负无穷)、NAN (非数字)、MIN(最小值)、MAX (最大值)。std::f32::consts 和 std::f64::consts 模块定义了一些常量:E(自然对数)、PI(圆周率)、SQRT_2(2 的平方根)等等。
各整数类型的取值范围:
- u8: [0, 2^8 –1] (0 ~ 255)
- u16: [0, 2^16-1] (0 ~ 65,535)
- u32: [0, 2^32-1] (0 ~ 4,294,967,295)
- u64: [0, 2^64-1] (0 ~ 18,446,744,073,709,551,615,约 1.8 千亿亿)
- i8: [−2^7, 2^7 −1] (−128 ~ 127)
- i16: [−2^15, 2^15 −1] (−32,768 ~ 32,767)
- i32: [−2^31, 2^31 −1] (−2,147,483,648 ~ 2,147,483,647)
- i64: [−2^63 , 2^63 −1] (−9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807)
- usize:[0,2^32 −1] (32 位系统) 或 [0, 2^64 −1] (64 位系统)
- isize: −2^31 至 2^31 −1, or −2^63 至 2^63 −1
| |
位运算
| 名字 | 运算符 | 说明 | 范例 |
|---|---|---|---|
| 位与 | & | 相同位都是 1 则返回 1 否则返回 0 | A & B ==2 |
| 位或 | | | 相同位只要有一个是 1 则返回 1 否则返回 0 | A|B = 3 |
| 异或 | ^ | 相同位不相同则返回 1 否则返回 0 | A ^ B = 1 |
| 位非 | ! | 把位中的 1 换成 0 , 0 换成 1 | (!B) 结果 -4 |
| 左移 | « | 操作数中的所有位向左移动指定位数,右边的位补 0 | (A « 1) 结果为 4 |
| 右移 | » | 操作数中的所有位向右移动指定位数,左边的位补 0 | (A » 1) 结果为 1 |
byte 字面量
- Rust 没有 byte 类型,u8 类型相当于 byte 类型;
- byte 字面量,表示 ASCII 字符;
- 书写方式:
b'x',b 表示是 byte;
| ASCII 字符 | byte 字面量的书写 | 相当于的数值 |
|---|---|---|
| 单引号 ' | b’'' | 39_u8 |
| 反斜杠 \ | b'\' | 92_u8 |
| 换行 | b'\n' | 10_u8 |
| 回车 | b'\r' | 13_u8 |
| 制表符 Tab | b'\t' | 9_u8 |
字符(char)
- 用单引号
''来引用; - Rust 的 char 表示一个 Unicode 字符;
- 每个 char 固定为 4 个 byte,32bit;
- UNICODE 编码;
- char 不能和任何其他类型之间进行隐式转换;
- 使用
as运算符将 char 转换为整数类型; - 对于小于 32 位的类型,字符值的高位将被截断:
- 只有 u8 能用 as 转换为 char。
- 如果想用 u32 位转换为 char,可以用 std 库里的
std::char::from_u32()函数,返回值是Option<char>类型 - char 类型的书写是用单引号引起来,字符串是用双引号引起来:
- char 类型的值包含范围为 0x0000 到 0xD7FF 或 0xE000 到 0x10FFFF 的 Unicode 码位。
- 对于其他数值,Rust 会认为是无效的 char 类型,出现编译异常。
| |
char 类型与 byte 字面量,String 类型区别:
'C': char 类型,在 stack 上开辟 4 字节空间,把字母 C 的 Unicode 码0x 00 00 00 43存入;b'C':byte 型,在 stack 上开辟 1 字节空间,把字母 C 的 ASCII 码0x43存入;"C":String, 在 heap 内存上开辟 N 字节空间(N 一般是字母 C 的字节数 1),然后在 stack 内存上开辟 12 字节空间(此处以 32 位平台为例):- 4 个字节存放堆内存放置数据的指针,
- 4 个字节存放字符串在内存中开辟的空间 N;
- 4 个字节存放字符串当前使用的空间;
特殊基本类型
never类型
never类型,即!,也称底类型;表示永远不可能有返回值的计算类型;
代表
无;没有值;
是其他任意类型的子类型;
可以等价于任意类型;
ZST类型
零大小类型(Zero sized Type,ZST),值就是其本身,运行时并不占用内存空间(不在栈、堆中);
**单元类型**和**单元结构体**大小为零,由单元类型组成的数组大小也是零。代表“
空”。
胖指针(fat pointer)
由一个指针+一个代表数据长度的部分组成;
size是指针大小的2倍;
复合类型
复合(compound)类型由多个值组合而成。复合类型包括:
Tuple: 多个类型的值组合进一个类型;Struct:Enum: 多种数值中的一种;Union:
元组(Tuple)
元组是一个将多个其他类型的值组合进一个复合类型的主要方式。
- 包含在
()中的,分隔的值列表(T1, T2, ...); - 元组长度固定,长度不会增大或缩小;
- 元组分配在栈空间;
| |
结构体(Struct)
Rust 中的结构体关键字struct
Rust 提供了 3 种结构体:
- 具名结构体:结构体的每个字段拥有名称;
- 元组结构体: 结构体的字段没有名称;
- 单元结构体: 结构体不包含任何字段;
| |
枚举(Enum)
enum用于表示多种可能数值中的一种;enum的多个值共用一个存储空间;
| |
联合体(Union)
union和 enums 类似,但没有标签;union的所有字段共享同一段存储;union的尺寸由其尺寸最大的字段的尺寸所决定;union字段的读取必须放在非安全(unsafe)块里;union没有“活跃字段(active field)”。每次访问联合体只是用所指定的字段的类型解释此联合体的存储;
| |
集合类型
集合类型由多个相同类型的值组成,包括:
- 数组(array):
- 向量(vector):
数组(Array)
在一块连续空间内存中,存储了一系列的同样类型的数据
- 数组的类型为
[T; N],T表示元素类型,N为元素个数; - 只有当 T, N 都相同时,数组的类型才相同;
- Rust 数组大小固定,一旦声明,其长度不会增大或缩小;
- 数组位于
栈上; - array 索引访问错误会产生 panic;
array只能储存一种类型的数据,无法存储不同类型的数据;
| |

向量(Vector)
Vec是动态数组,会自动增长,不会自动收缩;Vector 包含两部分:
栈上的 vector 结构体:
- 指向堆上连续空间的首指针;
- 总元素个数;
- 已使用元素个数;
堆上的连续分配空间;
Vec<T>中的泛型T必须是Sized的;vector 把所有的元素放在一个分配在堆(heap)上的 array 上。当一个新元素被 push 进来时,vector 检查 array 是否有足够的剩余空间。如果空间不足,vector 就分配一个更大的 array,将所有的元素都拷贝到这个新的 array 中,然后释放旧的 array

| |
切片(Slice)
切片(slice)是对数组(array)或 vector 的一个临时视图;
slice 是动态大小类型,无法直接被使用,只能通过引用形式来访问;
slice 形式:
[T];Slice 继承了 Array 的 length、item 等很多的方法;
slice 包含 2 个字段:
- 指向 slice 起始元素的头指针;
- slice 中元素的个数;
| |
范围(Range)
- Range 是 Rust 内置的用于表示一个范围的数据类型;
- Range 数据类型位于
std::ops::RangeXXX内; - 每个范围都是一个迭代器,可用 for 循环打印范围内的元素;
Rust 支持范围操作符,有以下几种表示范围的操作符:
| 范围表达式 | 类型 | 表示的范围 |
|---|---|---|
| start..end | std::ops::Range | start ≤ x < end |
| start.. | std::ops::RangeFrom | start ≤ x |
| ..end | std::ops::RangeTo | x < end |
| .. | std::ops::RangeFull | - |
| start..=end | std::ops::RangeInclusive | start ≤ x ≤ end |
| ..=end | std::ops::RangeToInclusive | x ≤ end |
| |
常用数据类型
字符串
Rust 中的字符串包括两种:str和 String。
str(字符串字面量)
str由核心语言提供core::str;常以引用的形式出现——
&str;胖指针,两部分:指向字符串序列的指针、记录长度的值。
静态不可变;
支持转义;
支持切片操作;
&str有两种产生方式:- 字符串字面量:
&str内存位于程序的预分配文本区,该区域为只读区域; - 字符串引用:为一个
String的切片引用,原String字符位于堆上;
- 字符串字面量:
| |
String(字符串)
String由标准库提供的std::String;位于堆(heap)上分配内存;
可增长的、可变的、有所有权;
String和&str都是 UTF-8 编码的;String->&str非常轻松,几乎没有开销;&str->String是需要在堆上请求内存的;String不支持通过下标访问,可转换为&str进行;
不是 char 数组, 而是 UTF-8变长序列;
ASCII 字符占一个字节 byte, 其余字符占多个不定长字节.
len()方法返回的是字节(byte)长度, 而非字符(char)长度chars().count()返回字符(char)长度一个栈上的 String 变量在内存中表示如下:
| |
哈希表(HashMap)
- 所有实现了
Eq和Hash的类型都可以作为 HashMap 的 key; - 通过
#[derive(PartialEq, Eq,hash)]可以快速的实现Eq和Hash。
| |
- Rust 中的 HashSet 实现非常简单就是
HashMap<T,()>;
| |
有序映射(BTreeMap)
- key有序的k-v存储结构;
- 底层使用BTree;
- 通过迭代器可按 key 顺序访问 BtreeMap 中的所有元素;
| |
有序集合(BTreeSet)
- BTreeSet 为有序集合, 和 hashset 区别在于集合中的元素为有序集;
| |
双端队列(VecDeque)
- 基于可扩张的环形缓冲双端队列;
二叉堆/优先队列(BinaryHeap)
- BinaryHeap 是 rust 中的;
- BinaryHeap 默认为大端堆, 即最大值在堆顶, 通过使用
Reverse得到小端堆;
| |
高级类型
类型别名
Rust使用
type关键字来给予现有类型另一个名字;type定义的类型别名拥有和原类型同一类型;
类型别名的主要用途是减少重复;
| |
never type
dyn
sized
参考
- https://www.codemore.top/p/ce5ae822-e775-351d-830c-994110faf023/
- https://unpluggedcoder.me/2019/08/15/Rust%E5%85%A5%E9%97%A8%E5%A4%B1%E8%B4%A5%E4%B9%8BOwnership/
- Rust 之路(2)——数据类型 上篇 - sumyuan - 博客园
- https://doc.rust-lang.org/std/collections/struct.VecDeque.html
- https://rustwiki.org/zh-CN/edition-guide/rust-2018/data-types/union-for-an-unsafe-form-of-enum.html
- https://rustwiki.org/zh-CN/std/collections/binary_heap/struct.BinaryHeap.html