能否声明某 trait 的实现无需满足 Sized 约束?
搞定Rust里Trait默认绑定Sized的麻烦事
我明白你的困扰——给动态大小类型(比如[u32])实现了Trait,结果每个接收该Trait的函数都要手动加?Sized约束,实在太繁琐了。咱们来一步步解决这个问题:
为什么直接写trait Foo: ?Sized会报错?
首先,Rust的Trait默认是给**固定大小类型(Sized)**设计的,默认隐含Self: Sized约束。如果你之前尝试写trait Foo: ?Sized却报错,大概率是旧版本Rust的限制(现在稳定版已经支持这种写法了),或者是方法签名里有隐含的Sized依赖——不过你的foo方法用的是&self,完全兼容非Sized类型,所以现在的写法是可行的。
一次性解决:让Trait本身支持非Sized类型
正确的做法是在Trait定义时显式取消默认的Sized约束,这样所有实现该Trait的类型(包括DST)都能被函数正常接收,不用再重复加约束。修改后的代码如下:
// 给Trait加上?Sized约束,允许非固定大小类型实现它 trait Foo: ?Sized { fn foo(&self) -> u32; } impl Foo for [u32] { fn foo(&self) -> u32 { self[0] } } // 这里不需要再加+ ?Sized了! fn bar<T>(f: &T) -> u32 where T: Foo, { f.foo() + 1 } fn main() { let f: &[u32] = &[42]; bar(f); }
原理是什么?
Rust里,Trait默认会要求Self必须是Sized——这是为了避免很多隐含的错误。但当我们给Trait加上: ?Sized,就相当于告诉编译器:“这个Trait允许非固定大小的类型来实现”。
这样一来,所有接收T: Foo的函数,都会自动继承这个宽松的约束,不再默认强制T是Sized类型,完美解决了你重复加约束的麻烦。
注意事项:方法的兼容性
如果你的Trait里有需要接收self(值传递)的方法,那这类方法仍然只能被Sized类型实现——毕竟动态大小类型没法被值传递。比如:
trait Foo: ?Sized { fn foo(&self) -> u32; // 给方法单独加Sized约束,只有固定大小类型能实现它 fn consume(self) -> u32 where Self: Sized; }
这种情况下,[u32]还是能正常实现foo方法,但consume方法就和它无关了,这完全符合Rust的安全规则。
内容的提问来源于stack exchange,提问作者Pierre-Antoine
相关产品推荐
相关产品推荐

