Rust 数据类型 完整超详细知识点
Rust 是静态强类型、编译期类型检查 语言,所有变量、参数、返回值必须确定类型;支持类型推导,但不能动态改变变量类型。
Rust 数据类型分为两大分支:
- 标量类型(Scalar) :单个值;整数、浮点数、布尔、字符
- 复合类型(Compound) :把多个值组合在一起;元组、数组 再延伸:切片、字符串、结构体、枚举、联合体、智能指针、动态类型。
关键概念:栈 vs 堆
- 栈:固定已知大小,快速,自动入栈出栈;
- 堆:运行时分配,大小可变,需要指针访问;
- 标量、固定大小复合类型大多放栈;String、Vec、Box 数据存堆。
一、标量类型 Scalar
1. 整数类型 Integer
| 位数 | 有符号 i | 无符号 u | 范围 |
|---|---|---|---|
| 8bit | i8 | u8 | i8:‑128 |
| 16bit | i16 | u16 | ±32768 / 0‑65535 |
| 32bit | i32 | u32 | i32 Rust默认整数 |
| 64bit | i64 | u64 | 常用时间、id |
| 128bit | i128 / u128 | 大数值 | |
| arch | isize / usize | 指针宽度;32位程序32bit,64位64bit;数组索引、集合长度必须usize |
字面量写法
ini
let a = 10; // 默认 i32
let b:u64 = 100;
let c = 0xff; // 十六进制
let d = 0o77; // 八进制
let e = 0b1010; // 二进制
let f = b'A'; // u8字节字面量
let g = 1_000_000; // 下划线数字分隔,仅可读性
整数溢出(非常重要)
Rust 编译模式行为不同:
- debug模式(开发) :整数溢出直接 panic,防止bug;
- release模式(--release) :回绕包装(wrapping) ,如
u8::MAX +1 → 0,不会panic。
安全处理溢出的4套API:
scss
let x:u8 = 255;
x.wrapping_add(1); // 包装回绕,返回0
x.saturating_add(1); // 饱和运算,到最大值不再上涨 →255
x.checked_add(1); // Option<u8>,溢出返回None
x.overflowing_add(1); // (值,溢出bool)
索引必须
usize;裸内存偏移常用isize。
2. 浮点 Float
f32 单精度、f64 双精度(Rust浮点数默认 f64) 遵循 IEEE‑754。
ini
let f1 = 3.14; // f64
let f2:f32 = 2.5;
let inf = f64::INFINITY;
let nan = f64::NAN;
⚠️ NaN 不等于任何值包括自己,判断不能用 ==,要用 .is_nan()。 浮点数不要直接 == 判断相等,用误差范围比较。
3. 布尔 bool
仅两个值:true / false,占1字节。
csharp
let ok:bool = true;
// 条件必须是bool,不支持 if(非0),不能用数字直接当条件
if ok {}
4. 字符 char
- 4字节(Unicode标量值) ,不是1字节!可存中文、emoji。
ini
let c:char = '中';
let emoji = '😀';
char 是单个Unicode字符;不等于字节;字符串是UTF‑8字节流。
二、基础复合类型 Compound
1. 元组 tuple (T1,T2,T3)
固定长度,每个位置类型可以不同;栈上存储。
rust
let t:(i32, f64, bool) = (10,3.14,true);
// 索引访问,从0开始
println!("{}", t.0);
// 解构
let (a,b,c) = t;
// 单元元组 (),零大小类型 ZST,返回无返回值函数的返回类型
let unit:() = ();
2. 数组 [T; N]
- 固定长度,编译期确定N,所有元素类型相同,栈分配
- 类型标记
[i32;5],T是元素类型,N是长度。
ini
let arr:[i32;3] = [1,2,3];
let arr2 = [0;10]; // 10个0
// 下标索引 arr[0],索引必须 usize;越界运行时panic
println!("{}", arr[0]);
❗数组长度编译期常量,运行时变量不能改变数组N。 运行时可变长度集合用
Vec<T>。
3. 切片 slice &[T] / &mut [T]
动态视图,不拥有所有权;借用已有数组/Vec一段连续内存
- 胖指针:(数据指针, 元素个数)
ini
let arr = [1,2,3,4];
let s:&[i32] = &arr[1..3]; // [2,3]
&str 是字符串切片,是 &[u8] 的别名。
4. 字符串相关(高频易错)
1)&str:字符串切片
- 借用;UTF‑8;不拥有数据;胖指针;
- 字符串字面量
let s = "abc"类型是&'static str,存在程序二进制只读段。
2)String
- 拥有所有权;堆上分配可变UTF‑8字符串;
ini
let mut s = String::from("hello");
s.push_str(" world");
重点:Rust字符串是UTF‑8字节流,不是char数组 ,不能直接用数字下标取字符! 按字节索引
s[0]会panic,多字节中文会破坏字符边界。 遍历字符:s.chars();遍历字节:s.bytes()。
&String可以自动强转成&str(解引用强制多态)。
&str 与 String 对比
| &str | String | |
|---|---|---|
| 所有权 | 借用,不拥有 | 拥有,堆分配 |
| 可修改 | 不可变 | 可追加修改 |
| 存储位置 | 二进制段 / 堆借用视图 | 堆 |
| 转换 | String.as_str() → &str | String::from(slice) |
三、自定义类型:struct、enum、union
1. 结构体 struct
命名结构体(命名字段)
rust
#[derive(Debug,Clone)]
struct Point {
x:i32,
y:i32,
}
let p = Point{x:10,y:20};
println!("{}",p.x);
元组结构体(字段无名字,只有类型)
rust
struct Color(u8,u8,u8);
let c = Color(255,0,0);
println!("{}", c.0);
单元结构体,无字段,零大小ZST
ini
struct Marker;
let m = Marker;
repr(C) 重要!FFI场景
css
#[repr(C)]
struct S { a:i32; b:f64; }
保证内存布局对齐和C语言一致,bindgen生成FFI结构体全部带#[repr(C)]。 默认Rust结构体布局不保证顺序,编译器可重排字段。
2. 枚举 enum
每个枚举变体可以:无数据、元组、结构体。
rust
#[derive(Debug)]
enum Msg {
Quit, // 单元变体
Move{i:i32,j:i32}, // 结构体变体
Write(String), // 元组变体,持有数据
}
let m = Msg::Write("hi".into());
标准库高频枚举:Option<T>、Result<T,E>
scss
enum Option<T> { None, Some(T) }
enum Result<T,E> { Ok(T), Err(E) }
match 匹配枚举,必须穷尽所有分支。
C兼容枚举 #repr(u32)
ini
#[repr(u8)]
enum Color { Red=1,Green=2 }
指定底层存储整数,用于FFI和bindgen。
3. union 联合体(unsafe)
同一内存位置存放多种不同类型,内存重叠;必须unsafe访问,主要用于FFI。
rust
union U {
i:i32,
f:f32,
}
四、类型别名 type
只是别名,不是新类型,等价原有类型:
ini
type UserId = u64;
let id:UserId = 100;
区别于 newtype模式(元组结构体包装):
c
struct UserId(u64); // 全新类型,不能直接和u64混用
五、所有权相关类型(容器、智能指针)
1. 集合容器(标准库)
Vec<T>:动态可变数组,堆分配;Vec<T>拥有全部元素所有权VecDeque<T>:双端队列HashMap<K,V>哈希表;BTreeMap<K,V>有序树HashSet<T>/BTreeSet<T>
2. 智能指针(实现Deref/Drop trait)
| 类型 | 作用 | Send/Sync |
|---|---|---|
Box<T> |
把T放到堆上;所有权转移 | ✅✅ |
Rc<T> |
单线程引用计数共享所有权 | ❌❌ |
RefCell<T> |
单线程内部可变性,运行时借用检查 | ❌❌ |
Arc<T> |
多线程原子引用计数共享 | ✅✅ |
Mutex<T> |
多线程内部可变性,互斥锁 | ✅如果T:Send |
RwLock<T> |
读写锁 | ✅如果T:Send |
Rc<RefCell<T>>:单线程共享可变;Arc<Mutex<T>>多线程共享可变。
3. 裸指针
*const T 不可变裸指针;*mut T可变裸指针;无借用检查,必须unsafe,FFI、bindgen大量生成裸指针。
裸指针和引用
&T不一样,引用一定有效;裸指针可以野指针。
六、函数相关类型
-
函数类型
fn(i32)->bool:普通函数指针,静态,可复制。 -
闭包类型 :每个闭包生成唯一匿名类型;可被
Fn/FnMut/FnOncetrait抽象。Fn:捕获不可变引用;可多次调用FnMut:捕获可变引用;可多次调用FnOnce:捕获所有权;只能调用一次
-
impl Trait:返回静态匿名实现;dyn Traittrait对象(胖指针,动态分发)。
七、ZST 零大小类型
大小为0字节,如 ()、单元结构体 struct Marker;。 不占内存;可以做标记类型;泛型中经常见到。
八、类型转换规则(重点)
1. 强转 as
仅基础标量可用as;不做安全校验,截断直接发生。
ini
let x:i32 = 100;
let y:u8 = x as u8;
⚠️大整数转小整数直接截断,不会panic。
2. 隐式转换很少,Rust尽量禁止隐式转换
允许的少数隐式:
- 解引用强制多态:
&String → &str - 数组/Vec → 切片
&Vec<T> → &[T] Box<T>解引用;impl Trait接收实现该trait的类型。
3. trait转换:From / Into
安全语义转换,优先使用,替代as。
ini
let s = String::from("abc");
let num:u64 = 10u32.into();
九、生命周期与类型;泛型类型
- 生命周期不是类型,是类型的注解 ,标记引用存活时间,
'a。&'a T、&'a mut T。 - 泛型:
<T,U>,编译期单态化,每个具体类型生成一份代码。
r
fn foo<T>(v:T) -> T {v}
- trait bound:
T:Debug+Clone约束泛型能力。 - 关联类型:
trait Iterator { type Item; }trait内部定义类型。
十、类型推导、标注位置
Rust尽可能推导,但是下面场景必须手动标注类型:
- 空集合
Vec::new(),无法推导T;
rust
let v:Vec<i32> = Vec::new();
- parse解析,返回Result,需要目标类型;
css
let num:i32 = "123".parse().unwrap();
- 多个类型分支,编译器无法统一。
标注语法两种:
ini
let x:i32 = 10;
let y = 10_i32; // 后缀字面量标注
十一、内存布局关键知识点(FFI/bindgen必备)
- 默认Rust结构体字段顺序不保证 ,编译器重排优化;FFI必须
#[repr(C)]。 - repr(C)按照C语言对齐规则,存在填充padding字节。
- repr(packed)取消对齐(极度危险,容易未对齐访问UB)。
- repr(transparent):新类型和内部成员内存布局完全一致。
csharp
#[repr(transparent)]
struct Id(u64);
十二、常见易错点汇总
char占4字节,不是1字节;字符串是UTF‑8字节流,不能直接数字下标取字符。usize/isize跟随系统架构,数组索引必须usize。- debug溢出panic,release溢出回绕,业务要用checked/saturating系列。
&str借用;String拥有所有权;两者不能混淆。- 元组结构体
Newtype是新类型;type只是别名。 - 裸指针无安全保证,必须unsafe;引用
&T永远有效。 - 结构体默认布局未定义,跨语言FFI一定要
#[repr(C)]。 - 不要用浮点数直接
==判等。 - 数组
[T;N]长度编译期常量;运行时变长选Vec<T>。 Rc不能跨线程;多线程共享必须Arc。
十三、速记总览
标量四件套:整数、浮点、bool、char; 复合:元组不同类型,数组固定长同类型;切片是视图不拥有; &str借用只读;String堆上可变拥有; struct自定义数据,enum可变多变体;union仅FFI unsafe; type别名不造新类型;newtype元组结构体创建全新类型; Box堆分配;Rc单线程共享;Arc多线程共享;RefCell/Mutex内部可变性; as做强制转换;From/Into安全语义转换; repr(C)对齐C兼容,默认结构体布局不保证; 泛型编译单态化;生命周期标记引用有效期。
如果你需要,我可以给你一份:Rust数据类型速查表(可复制做笔记) ,或者做一份面试高频题。