rust语言Sized特征
Rust 中的
Sized Trait(特征)是一个非常基础但至关重要的概念。它是一个标记 Trait(Marker Trait),没有包含任何方法,其唯一目的是告诉编译器一个类型是否具有在编译时确定的固定大小。1. Sized 的定义与作用
在 Rust 中,几乎所有你在日常编程中使用的类型默认都是
Sized 的:- 具有固定大小的类型:
i32,bool,[u8; 10](固定长度数组),&str(引用本身是固定大小的指针)。 - 大多数结构体和枚举:只要它们内部的所有字段都是
Sized的,它们就是Sized的。
Sized Trait 使得编译器知道需要在栈上为该类型分配多少内存。2. 动态大小类型 (DSTs)
有些类型的大小直到运行时才能确定,它们就是“动态大小类型”(Dynamically Sized Types, DSTs),这些类型没有实现
Sized Trait。最常见的 DSTs 是:
- 切片 (
[T]):一个未知长度的 T 序列。 - 字符串切片 (
str):一个未知长度的 UTF-8 字符串。 - Trait 对象 (
dyn Trait):一个实现了某个 Trait 的未知具体类型的实例。
3. Sized 的默认泛型约束
在 Rust 中,所有的泛型函数默认都自动添加了一个
T: Sized 的约束。这意味着当你编写一个泛型函数时,编译器假设你只能使用大小已知的类型:// 这是一个泛型函数,默认等同于 fn generic_function<T: Sized>(item: T) fn generic_function<T>(item: T) { // 编译器知道 T 的大小,可以在栈上传递 item } // let slice: [i32]; // 错误:[i32] 不是 Sized,不能直接作为变量
4. 使用 ?Sized 来放宽约束
如果你想编写一个可以接受 DSTs 的泛型函数,你需要使用特殊的
?Sized(读作“T 可能不是 Sized”)语法来取消默认约束。通常,你会将参数类型修改为引用,因为你不能直接传递 DST 值,但可以传递指向它们的胖指针(包含长度信息的指针)。
// 使用 ?Sized 允许 T 是 [u8]、str 或其他 DSTs fn take_anything<T: ?Sized>(item: &T) { // 现在我们可以接受 &str, &[u8] 等类型 println!("项目大小(运行时确定):{}", std::mem::size_of_val(item)); } fn main() { take_anything("Hello"); // T 是 str (不是 Sized) take_anything(&[1, 2, 3, 4]); // T 是 [i32; 4] 或 [i32] (如果作为切片传递) take_anything(&10i32); // T 是 i32 (是 Sized) }
总结
SizedTrait 是一个标记,表示类型大小在编译时已知。[T]和str是没有实现Sized的 DSTs。- 所有泛型函数默认要求
T: Sized。 - 使用
?Sized可以取消这个默认要求,允许函数使用动态大小类型(通常通过引用传递)。
浙公网安备 33010602011771号