我了解the rules何时可以将特征转化为特征对象,但是我不理解为什么存在这些规则。
例如:
trait Resource {
const RESOURCE_ID: u64;
}
trait ResourceStatic {
fn static_id() -> u64;
}
trait ResourceInstance {
fn resource_id(&self) -> u64;
}
struct MyResource {}
impl Resource for MyResource {
const RESOURCE_ID: u64 = 123;
}
impl ResourceStatic for MyResource {
fn static_id() -> u64 {
123
}
}
impl ResourceInstance for MyResource {
fn resource_id(&self) -> u64 {
123
}
}
在我看来,这三个特征基本上都封装了相同的功能。那么为什么不允许这些:
let _: Box<dyn Resource> = Box::new(MyResource{});
let _: Box<dyn ResourceStatic> = Box::new(MyResource{});
但这是吗?
let _: Box<dyn ResourceInstance> = Box::new(MyResource{});
有人可以解释一下幕后发生的事情吗,以免看起来有些武断?
答案 0 :(得分:4)
什么是特征对象?是
此定义足以说明ResourceInstance
和Resource
不起作用的原因,ResourceStatic
起作用。
ResourceInstance
trait ResourceInstance {
fn resource_id(&self) -> u64;
}
可以将这个特征变成一个对象,因为即使具体类型未知,您仍然可以在实现该特征的值上调用resource_id
(通过将其作为self
参数传递)。
ResourceStatic
trait ResourceStatic {
fn static_id() -> u64;
}
此特征不能成为对象,因为static_id
可以被称为而没有值,这意味着要调用static_id
,您必须知道具体类型。
对于每种特征对象类型(例如dyn ResourceStatic
),编译器会自动生成相应特征(ResourceStatic
)的实现。此自动实现使用在trait方法中作为self
类型的一部分传递的vtable指针。如果没有self
类型,则没有vtable指针,并且编译器无法自动实现该方法。 Rust中没有“裸vtable指针”。
为更好地理解这一点,请设想dyn ResourceStatic
是有效类型。 <dyn ResourceStatic>::static_id()
是做什么的?它不能遵循具体类型的实现,因为它没有价值,因此也没有具体类型。我们是否可以得出结论,dyn ResourceStatic
没有实现 ResourceStatic
?这显然是错误的。还是dyn ResourceStatic
有自己的ResourceStatic
实现,没有遵循某种具体类型?这也是没有道理的,因为dyn ResourceStatic
的重点是要代表一种具体的类型。
Rust解决此问题的方法只是拒绝将dyn ResourceStatic
作为类型。
Resource
trait Resource {
const RESOURCE_ID: u64;
}
由于ResourceStatic
不能出于相同的原因,无法将此特征制成对象:因为特征对象类型dyn Resource
不可能自动满足特征要求。
如果要在类型Self
上进行动态分派,则需要一个self
参数进行分派。