Rust 数据类型
简介
Rust 的数据分为 标量(scalar)
、复合(compound)
和 集合
3 种类型:
类型写法 | 描述 | 值举例 |
---|---|---|
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 个字节存放字符串当前使用的空间;
复合类型
复合(compound)类型由多个值组合而成。复合类型包括:
Tuple
: 多个类型的值组合进一个类型;Struct
:Enum
: 多种数值中的一种;Union
:
元组(Tuple)
元组是一个将多个其他类型的值组合进一个复合类型的主要方式。
- 包含在
()
中的,
分隔的值列表(T1, T2, ...)
; - 元组长度固定,长度不会增大或缩小;
- 元组分配在栈空间;
|
|
结构体(Struct)
Rust 中的结构体
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