我有一个简单的防锈代码:

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>>

这是包含traitDnsRecord的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,以防止出现此错误。

07-26 04:22