rust语言学习笔记Trait(十二)Sized、?Sized (大小限制)

Sized 是 Rust 中一个极其特殊的标记 Trait(Marker Trait),它既没有方法,也极少需要手动实现,但却深刻地影响着 Rust 的类型系统、内存布局和 trait 对象的使用方式。

1、什么是 Sized

Sized 的定义极其简单,位于 std::marker 模块中:

rust 复制代码
pub trait Sized { }

一个类型在‌编译期具有固定且已知的大小 ‌。Rust 中绝大多数类型都是 Sized 的,包括所有基本类型、结构体、枚举、数组、元组等。

如果一个类型的大小在编译期无法确定,它就被称为‌动态大小类型(DST, Dynamically Sized Type)。典型的 DST 包括:

  • 切片类型 [T]
  • 字符串切片 str(不是 &str
  • trait 对象 dyn Trait
  • 包含一个 DST 作为最后一个字段的结构体
rust 复制代码
// 这些都是 DST,无法直接使用
let s: str = *"hello";            // 编译错误:size 未知
let arr: [i32] = [1, 2, 3];       // 编译错误:size 未知
let dyn_obj: dyn Display = ...;   // 编译错误:size 未知

由于 DST 的大小未知,它们无法被放在栈上,也不能作为函数参数按值传递。只能在‌指针后面 ‌使用它们,比如 &str&[T]Box<dyn Trait> 等。

2、隐式 Sized 绑定

Rust 的类型参数‌默认是 Sized ‌。这意味着当你写一个泛型函数时,编译器实际上帮你在内部添加了 Sized 约束:

rust 复制代码
// 你写的代码
fn foo<T>(x: T) { ... }

// 编译器实际看到的
fn foo<T: Sized>(x: T) { ... }

这种隐式绑定覆盖了以下场景:

  • 泛型类型参数 T
  • 泛型结构体/枚举中的字段
  • impl Trait 的返回类型

3、 使用 ?Sized 解除限制

当你需要在泛型中接受 DST 时,需要使用特殊语法 ?Sized,意为 T 可以是 Sized 的,也可以不是。

rust 复制代码
// 解除 Sized 限制,T 可以是 DST
fn bar<T: ?Sized>(x: &T) {
    // x 是指针,所以即使 T 是 DST 也没问题
}

?Sized 只能在以下位置使用:

  • 泛型类型参数:T: ?Sized
  • 结构体泛型参数的最后一个字段:struct S<T: ?Sized> { tail: T }

不能‌在关联类型、trait 自身定义或函数返回值中使用。

rust 复制代码
use std::fmt::Debug;

fn print_test<T: Debug + ?Sized>(t: &T) {
    println!("{:?}", t);
}

fn main() {
    print_test("ssss");
    print_test(&[2, 5, 6]);
    print_test(&35);
}

4、标准库中的应用

类型/模块 应用方式 说明
Box<T> impl<T: ?Sized> Box<T> Box 可以指向堆上的 DST,如 Box<[i32]>Box<dyn Error>
Rc<T> / Arc<T> impl<T: ?Sized> Rc<T> 引用计数指针也可以指向 DST。
std::fmt::Debug trait Debug: ?Sized 允许对 &str[i32] 等切片直接调用 .fmt()
AsRef<T> impl<T: ?Sized, U: ?Sized> AsRef<U> for T 许多转换逻辑需要处理不定长类型。

5、Sized?Sized 的使用

  1. 默认不动 ‌:在绝大多数泛型编程中,保持默认的 Sized 约束。这保证了类型可以按值传递、存储在栈上,且性能最优。
  2. 需要灵活性时用 ?Sized
    • 当你的函数接收的是‌引用 ‌(&T)或‌智能指针 ‌(Box<T>),且你希望它能通吃"具体类型"和"切片/Trait对象"时。
    • 典型签名:fn foo<T: ?Sized>(x: &T)
  3. 设计 Trait 时注意 ‌:
    • 如果希望 Trait 能被用作 dyn Trait,不要给 Trait 本身加 Sized 约束。
    • 如果 Trait 中的某些方法依赖于静态大小(如返回 Self),给该方法加 where Self: Sized

理解 Sized?Sized 的核心在于明白:‌**Rust 默认追求静态确定的内存布局,而 ?Sized 是为了在必要时(通过指针间接访问)打破这一限制,以支持多态和切片操作。

相关推荐
potion()1 小时前
基于助睿平台的浏览器用户行为分析与流失预测 —— 数据加工实验
笔记·数据清洗·用户行为分析·助睿数智·商业数据分析·浏览器行为分析
玄米乌龙茶1231 小时前
思维导图笔记:RAG检索增强生成
笔记
bllovepigpig1 小时前
A÷文章浅读笔记 【规模化托管智能体:将大脑与双手分离】
笔记
꧁꫞꯭零꯭点꯭꫞꧂1 小时前
LangChain 提示词模板与链式调用笔记
人工智能·笔记·langchain
久菜盒子工作室1 小时前
徕木股份经营分析
科技·学习
问心无愧05131 小时前
ctf show web入门257
android·前端·笔记
songyuc2 小时前
Matplotlib&seaborn学习笔记
笔记·学习·matplotlib
Byron__2 小时前
JVM垃圾回收与调优核心面试笔记(引用计数/GC算法/CMS/G1/参数调优)
java·jvm·笔记·面试
唯情于酒2 小时前
IdentityServer4学习笔记
笔记·学习