直接回答:对象安全指一个 trait 能否用于 dyn Trait 动态分发。根本原因是 vtable 条目必须在编译期确定,而编译器不知道具体类型。主要规则:方法不能有泛型参数(vtable 无法容纳无限多单态化版本);不能返回 Self;必须能通过接收者分发(没有 self 接收者的关联函数无处挂载);trait 自身不能带泛型参数、不能有关联常量。带 where Self: Sized 的方法被豁免。

展开解析:经典例子:Clone 不对象安全(clone 返回 Self);FromStr 不对象安全(无接收者且返回 Self);而 Iterator 在指定关联类型后(dyn Iterator<Item = i32>)是对象安全的——关联类型可以固定在 dyn 类型里。补救手法:给泛型方法加 where Self: Sized 移出 vtable;返回 Self 改为 Box<Self> 或拆出关联类型;用 dyn-clone 这类宏实现可克隆的 trait object。vtable 里还存有 size、align 和 drop 指针,所以 Box<dyn Trait> 不知道具体类型也能正确析构。

trait Storage {
    fn get(&self, k: &str) -> Option<Vec<u8>>; // 对象安全
    fn keys<T>(&self) -> T where Self: Sized { todo!() } // 被豁免
}

追问方向:为什么关联类型不破坏对象安全而泛型方法破坏?vtable 里的 drop 信息解决了什么问题?trait upcasting 是什么? (约 600 字)