Rust 数据类型 完整超详细知识点

Rust 数据类型 完整超详细知识点

Rust 是静态强类型、编译期类型检查 语言,所有变量、参数、返回值必须确定类型;支持类型推导,但不能动态改变变量类型。

Rust 数据类型分为两大分支:

  1. 标量类型(Scalar) :单个值;整数、浮点数、布尔、字符
  2. 复合类型(Compound) :把多个值组合在一起;元组、数组 再延伸:切片、字符串、结构体、枚举、联合体、智能指针、动态类型。

关键概念:栈 vs 堆

  • 栈:固定已知大小,快速,自动入栈出栈;
  • 堆:运行时分配,大小可变,需要指针访问;
  • 标量、固定大小复合类型大多放栈;String、Vec、Box 数据存堆。

一、标量类型 Scalar

1. 整数类型 Integer

位数 有符号 i 无符号 u 范围
8bit i8 u8 i8:‑128127;u8:0255
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 编译模式行为不同:

  1. debug模式(开发) :整数溢出直接 panic,防止bug;
  2. 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. 集合容器(标准库)

  1. Vec<T>:动态可变数组,堆分配;Vec<T>拥有全部元素所有权
  2. VecDeque<T>:双端队列
  3. HashMap<K,V> 哈希表;BTreeMap<K,V>有序树
  4. 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不一样,引用一定有效;裸指针可以野指针。


六、函数相关类型

  1. 函数类型 fn(i32)->bool:普通函数指针,静态,可复制。

  2. 闭包类型 :每个闭包生成唯一匿名类型;可被 Fn/FnMut/FnOnce trait抽象。

    • Fn:捕获不可变引用;可多次调用
    • FnMut:捕获可变引用;可多次调用
    • FnOnce:捕获所有权;只能调用一次
  3. impl Trait:返回静态匿名实现;dyn Trait trait对象(胖指针,动态分发)。


七、ZST 零大小类型

大小为0字节,如 ()、单元结构体 struct Marker;。 不占内存;可以做标记类型;泛型中经常见到。


八、类型转换规则(重点)

1. 强转 as

仅基础标量可用as不做安全校验,截断直接发生

ini 复制代码
let x:i32 = 100;
let y:u8 = x as u8;

⚠️大整数转小整数直接截断,不会panic。

2. 隐式转换很少,Rust尽量禁止隐式转换

允许的少数隐式:

  1. 解引用强制多态:&String → &str
  2. 数组/Vec → 切片 &Vec<T> → &[T]
  3. Box<T> 解引用;impl Trait接收实现该trait的类型。

3. trait转换:From / Into

安全语义转换,优先使用,替代as。

ini 复制代码
let s = String::from("abc");
let num:u64 = 10u32.into();

九、生命周期与类型;泛型类型

  1. 生命周期不是类型,是类型的注解 ,标记引用存活时间,'a&'a T&'a mut T
  2. 泛型:<T,U>,编译期单态化,每个具体类型生成一份代码。
r 复制代码
fn foo<T>(v:T) -> T {v}
  1. trait bound:T:Debug+Clone约束泛型能力。
  2. 关联类型:trait Iterator { type Item; } trait内部定义类型。

十、类型推导、标注位置

Rust尽可能推导,但是下面场景必须手动标注类型

  1. 空集合 Vec::new(),无法推导T;
rust 复制代码
let v:Vec<i32> = Vec::new();
  1. parse解析,返回Result,需要目标类型;
css 复制代码
let num:i32 = "123".parse().unwrap();
  1. 多个类型分支,编译器无法统一。

标注语法两种:

ini 复制代码
let x:i32 = 10;
let y = 10_i32; // 后缀字面量标注

十一、内存布局关键知识点(FFI/bindgen必备)

  1. 默认Rust结构体字段顺序不保证 ,编译器重排优化;FFI必须#[repr(C)]
  2. repr(C)按照C语言对齐规则,存在填充padding字节。
  3. repr(packed)取消对齐(极度危险,容易未对齐访问UB)。
  4. repr(transparent):新类型和内部成员内存布局完全一致。
csharp 复制代码
#[repr(transparent)]
struct Id(u64);

十二、常见易错点汇总

  1. char占4字节,不是1字节;字符串是UTF‑8字节流,不能直接数字下标取字符。
  2. usize/isize跟随系统架构,数组索引必须usize。
  3. debug溢出panic,release溢出回绕,业务要用checked/saturating系列。
  4. &str借用;String拥有所有权;两者不能混淆。
  5. 元组结构体Newtype是新类型;type只是别名。
  6. 裸指针无安全保证,必须unsafe;引用&T永远有效。
  7. 结构体默认布局未定义,跨语言FFI一定要#[repr(C)]
  8. 不要用浮点数直接==判等。
  9. 数组[T;N]长度编译期常量;运行时变长选Vec<T>
  10. 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数据类型速查表(可复制做笔记) ,或者做一份面试高频题。

相关推荐
菜鸟谢1 小时前
Rust let / static / const 完整详解
后端
超超不吵吵1 小时前
Java AI转型实战(三):第一次调用大模型API,拿到AI回复
后端
名字还没想好☜1 小时前
Go 1.23 range-over-func 迭代器实战:自定义可迭代类型、提前退出与惰性求值
开发语言·后端·golang·go·迭代器
对象存储与RustFS1 小时前
给 Kubernetes 找一个对象存储后端:RustFS Helm 部署 + 应用接入实录
后端·云原生·kubernetes
用户8181870627461 小时前
第7章 死锁排查实录:jstack定位死锁的完整流程
java·后端
逻辑帧1 小时前
给 AI 时代找工作的同学一些实用建议
前端·后端
喵同志不止步于码农2 小时前
Java Caffeine 快速入门
java·开发语言·后端·并发·缓存一致性
东风破_2 小时前
NestJS CRUD 实战:用 Todos 模块打通 Controller-Service-Module 三层
后端
东风破_2 小时前
NestJS 框架入门:从工厂模式到模块化架构
后端