可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I've got this simplified Rust code:
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() {}
The intention is that DnsRecord
should be able to hold any struct implementing the DnsRecordData
trait, with the different structs representing A, AAAA, CNAME etc.
This fails with the error:
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
What's got me the most confused is that by removing the generics from DnsRecordData::write()
, it compiles just fine:
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() {}
If anyone can explain what I'm missing, I'd very much appreciate it.
回答1:
The intention is that DnsRecord
should be able to hold any struct implementing the DnsRecordData
trait
That's not what the code says.
Vec<DnsRecord<DnsRecordData>>
This is a vector of the struct DnsRecord
containing the trait DnsRecordData
. If you want "any struct implementing the DnsRecordData
trait", you need a generic:
pub struct DnsPacket<D> where D: DnsRecordData { pub answers: Vec<DnsRecord<D>>, }
Traits can be implemented, but they also have their own type. In order to create this type, the trait needs to be object-safe - Trait Object is not Object-safe error.
As the error message states, this trait cannot be a trait object because there are generic types on the method.
The first error states that DnsRecord
requires that whatever type it is parameterized with must implement DnsRecordData
. However, the type of the trait object doesn't actually implement that. Normally, you'd use a trait object via a reference (&DnsRecordData
) or a box (Box<DnsRecordData>
), both of which should implement the trait, preventing this error.
回答2:
The second error comes from the fact that you can't create trait objects for DnsRecordData
due to the trait not being "object-safe". This concept is explained in the trait objects section of The Rust Programming Language.
In your particular case, the trait contains a generic method. To create a trait object, the compiler has to synthesize a vtable for the trait, containing a function pointer for every method the trait has. But because the trait has a generic method, it effectively has as many methods as the method could be instantiated with, which is potentially infinite. Therefore, you cannot make a trait object for DnsRecordData
.