Rust中如何不封装直接将动态trait类型值存储为本地变量?
Rust 本地trait类型变量赋值问题解答
不存在直接将不同trait实现类型赋值给裸trait类型本地变量的方法,原因和可行的替代方案如下:
核心原因
Rust要求所有变量的大小在编译期必须是确定的:
dyn Checker属于动态大小类型(DST),它的实际大小由具体的实现结构体决定,编译期无法提前计算,因此不管是不是本地变量,都不能直接声明dyn Checker类型的栈变量。- 你之前尝试的
let checker: dyn Checker本身就不符合Rust的类型系统规则,才会抛出类型不匹配错误。
无堆分配的替代方案
如果你不想用Box<dyn Checker>做堆分配,可以使用栈上实例 + trait对象引用的方式实现,不需要额外包装智能指针:
fn check(value: &str, which: &str) -> bool { // 预先在栈上声明两种可能的实例变量,不提前初始化不会有额外开销 let short_checker: ShortChecker; let prefix_checker: PrefixChecker; // checker是固定大小的trait引用(胖指针,大小为2个usize) let checker: &dyn Checker = if which == "short" { short_checker = ShortChecker {}; &short_checker } else if which == "prefix" { prefix_checker = PrefixChecker { prefix: "xyzzy".to_string() }; &prefix_checker } else { panic!("Unknown option"); }; checker.check(value) }
方案说明
- 两个Checker实现的实例本身存储在栈上,没有任何堆分配开销,符合你不想额外包装的需求。
- 最终使用的
&dyn Checker是固定大小的胖指针,包含指向栈上实例的指针和指向虚表的指针,编译期可以确定大小,符合Rust的类型要求。 - 该方案的限制是trait引用的生命周期不能超过底层栈实例的生命周期,仅适用于本地作用域内使用的场景,如果需要转移所有权或者存储到结构体中,还是需要使用
Box<dyn Checker>等智能指针包装。
内容的提问来源于stack exchange,提问作者Troy Daniels
相关产品推荐
相关产品推荐

