Rust返回Box<dyn Packet>报E0038 trait无法转为对象问题
错误根本原因
Rust中只有满足对象安全规则的trait才能被封装为dyn trait对象,你遇到的E0038错误就是因为Packet trait违反了对象安全规则,具体有两处违规:
- 第一,
Packet的超约束包含Defaulttrait:Default的default()方法是无self接收者、返回Self类型的静态方法,无法通过trait对象的虚表调用,本身不属于对象安全的trait。 - 第二,
Packet自身定义了无self接收者的静态方法deserialize_gen:该方法返回Box<Self>,且调用时不需要实例,无法被集成到trait对象的虚表中,因此违反对象安全要求。
你之前修改为返回Box<dyn PacketHandler>可以正常编译,是因为PacketHandler自身的定义满足所有对象安全规则。
修复方案
要实现返回Box<dyn Packet>的需求,只需要将所有不符合对象安全要求的方法和约束,通过where Self: Sized标记为仅可在具体类型上调用,不会被纳入trait对象的虚表即可,修改后的代码如下:
// 移除超约束中对象不安全的Default,新增PacketHandler作为超约束匹配实现要求 pub trait Packet: PacketSerializer + ProtocolToID + PacketHandler { // 带&self接收者的方法符合对象安全要求,正常保留 fn serialize_with_id(&self, ver: &ProtocolVersion) -> Box<ByteBuf>; // 静态方法加where Self: Sized约束,排除在trait对象虚表之外,同时加Default约束 fn deserialize_gen(buf: &mut ByteBuf) -> Box<Self> where Self: Sized + Default; } impl<T: PacketSerializer + ProtocolToID + PacketHandler + Default> Packet for T { fn serialize_with_id(&self, ver: &ProtocolVersion) -> Box<ByteBuf> { let mut buf = Box::new(ByteBuf::new()); buf.write_var_int(self.resolve_id(ver)); self.serialize(&mut buf, ver); buf } fn deserialize_gen(buf: &mut ByteBuf) -> Box<Self> where Self: Sized + Default { let mut p: T = Default::default(); p.deserialize(buf); Box::new(p) } } // 该函数无需修改即可正常编译 pub fn invoke_packet_handler(id: i32, buf: &mut ByteBuf) -> Box<dyn Packet> { Box::new(clientbound::SetCompression { threshold: 256 }) }
修改后,deserialize_gen方法仍然可以正常在所有实现了Packet的具体类型上调用,只是无法通过dyn Packet对象调用,不影响普通使用,同时Packet trait满足对象安全要求,可以正常封装为dyn对象返回。
内容的提问来源于stack exchange,提问作者ripzyzz
相关产品推荐
相关产品推荐

