我有这个简化的Rust代码:
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<DnsRecordData>>,
}
fn main() {}
意图是DnsRecord
应该能够容纳任何实现DnsRecordData
特征的结构,其中不同的结构代表A,AAAA,CNAME等。
失败并显示错误:
error: the trait bound `DnsRecordData + 'static: DnsRecordData` is not satisfied [--explain E0277]
--> src/main.rs:14:5
|>
14 |> pub answers: Vec<DnsRecord<DnsRecordData>>,
|> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by `DnsRecord`
error: the trait `DnsRecordData` cannot be made into an object [--explain E0038]
--> src/main.rs:14:5
|>
14 |> pub answers: Vec<DnsRecord<DnsRecordData>>,
|> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: method `write` has generic type parameters
让我最困惑的是,通过从DnsRecordData::write()
删除泛型,它编译得很好:
use std::io::Result;
pub trait PacketBuffer {}
pub trait DnsRecordData {
fn write(&self, buffer: &mut PacketBuffer) -> Result<usize>;
}
pub struct DnsRecord<R: DnsRecordData + ?Sized> {
pub data: Box<R>,
}
pub struct DnsPacket {
pub answers: Vec<DnsRecord<DnsRecordData>>,
}
fn main() {}
如果有人能解释我所缺少的东西,我会非常感激。
答案 0 :(得分:10)
意图是
parse
应该能够容纳任何实现DnsRecord
特征的结构
这不是代码所说的。
DnsRecordData
这是包含特征 Vec<DnsRecord<DnsRecordData>>
的结构DnsRecord
的向量。如果你想要&#34;任何实现DnsRecordData
特征&#34;的结构,你需要一个通用:
DnsRecordData
特征可以实施,但它们也有自己的类型。要创建此类型,特征需要对象安全 - Trait Object is not Object-safe error。
正如错误消息所述,此特征不能是特征对象,因为该方法上存在泛型类型。
第一个错误表明pub struct DnsPacket<D>
where D: DnsRecordData
{
pub answers: Vec<DnsRecord<D>>,
}
要求参数化的任何类型都必须实现DnsRecord
。但是,特征对象的类型并没有实际实现。通常,您通过引用(DnsRecordData
)或框(&DnsRecordData
)使用特征对象,这两个特征都应该实现特征,从而防止出现此错误。
答案 1 :(得分:8)
第二个错误来自于您无法为DnsRecordData
创建特征对象,因为该特征不是&#34;对象安全&#34;。 trait objects section of The Rust Programming Language中解释了这个概念。
在您的特定情况下,特征包含一般方法。要创建特征对象,编译器必须合成特征的vtable,其中包含特征所具有的每个方法的函数指针。但是因为特征具有通用方法,所以它实际上具有与可以实例化的方法一样多的方法,这可能是无限的。因此,您无法为DnsRecordData
创建特征对象。