我有一个简单的防锈代码:
use std::io::Result;
pub trait PacketBuffer {}
pub trait DnsRecordData {
fn write<T: PacketBuffer>(&self, buffer: &mut T) -> Result<usize>;
}
pub struct DnsRecord<R: DnsRecordData + ?Sized> {
pub data: Box<R>,
}
pub struct DnsPacket {
pub answers: Vec<DnsRecord<dyn DnsRecordData>>,
}
其目的是
DnsRecord
应该能够保存实现DnsRecordData
特性的任何结构,不同的结构代表A、AAAA、CNAME等。此操作失败,错误为:
error[E0038]: the trait `DnsRecordData` cannot be made into an object
--> src/lib.rs:14:5
|
14 | pub answers: Vec<DnsRecord<dyn DnsRecordData>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `DnsRecordData` cannot be made into an object
|
= note: method `write` has generic type parameters
最让我困惑的是,通过从
DnsRecordData::write()
中删除泛型,它可以很好地编译:use std::io::Result;
pub trait PacketBuffer {}
pub trait DnsRecordData {
fn write(&self, buffer: &mut dyn PacketBuffer) -> Result<usize>;
}
pub struct DnsRecord<R: DnsRecordData + ?Sized> {
pub data: Box<R>,
}
pub struct DnsPacket {
pub answers: Vec<DnsRecord<dyn DnsRecordData>>,
}
如果有人能解释我错过了什么,我将非常感激。
最佳答案
其目的是DnsRecord
应该能够保存实现DnsRecordData
特性的任何结构
代码上不是这么说的。
Vec<DnsRecord<dyn DnsRecordData>>
这是包含trait
DnsRecord
的structDnsRecordData
的向量。如果您想要“任何实现DnsRecordData
特征的结构”,您需要一个泛型:pub struct DnsPacket<D>
where
D: DnsRecordData,
{
pub answers: Vec<DnsRecord<D>>,
}
特质可以实现,但它们也有自己的类型。为了创建这种类型,特征需要是对象安全的-Trait Object is not Object-safe error。
如错误消息所述,此特征不能是特征对象,因为方法上有泛型类型。
第一个错误指出
DnsRecord
要求用它参数化的任何类型都必须实现DnsRecordData
。然而,trait对象的类型实际上并没有实现这一点。通常,您会通过引用(&dyn DnsRecordData
)或框(Box<dyn DnsRecordData>
)使用trait对象,这两个引用都应该实现trait,以防止出现此错误。