【发布时间】:2019-04-08 16:47:54
【问题描述】:
我正在尝试收集实现特定特征的对象。
如果我使用返回值的特征,则此方法有效
use std::collections::BTreeMap;
struct World {
entities: Vec<usize>,
database: BTreeMap<usize, Box<ReadValue>>,
//database : BTreeMap<usize,Box<ReadEcs>>, // Doesn't work
}
struct SourceInputGateway {
entity_id: usize,
}
trait ReadValue {
fn read(&self) -> f32;
}
impl ReadValue for SourceInputGateway {
fn read(&self) -> f32 {
0.0
}
}
但是,如果我想将 Self 作为值返回,那么无论是作为方法模板参数还是关联类型,这都行不通
trait ReadEcs {
type T;
fn read(&self) -> &Self::T;
}
impl ReadEcs for SourceInputGateway {
type T = SourceInputGateway;
fn read(&self) -> &Self::T {
self
}
}
我想做的是有一个实现ReadEcs的类型映射,具体类型并不重要。
进一步澄清编辑
如果我通过添加来扩展示例
// Different sized type
struct ComputeCalculator {
entity_id : usize,
name : String,
}
impl ReadValue for ComputeCalculator {
fn read(&self) -> f32 {
1230.0
}
}
那我就可以了
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn read_write() {
let mut world = World::new();
world.database.insert(0,Box::new(SourceInputGateway{ entity_id : 1}));
world.database.insert(2,Box::new(ComputeCalculator{ entity_id : 2 , name : "foo".into() }));
for (k,ref v) in world.database {
let item : &Box<ReadValue> = v;
item.read();
}
}
}
但如果我更改或添加返回 Self 的 trait 方法,我就无法做到这一点。 我想了解一种在没有不安全指针的情况下绕过它的方法。
【问题讨论】:
-
Rust 是一种静态类型语言。每个表达式都有一个在编译时已知的类型。假设编译器允许
Box<dyn ReadEcs>类型的特征对象,并且您在变量x中有这样一个特征对象。现在表达式x.read()的类型是什么?试图回答这个问题应该清楚为什么这不起作用,并给出如何解决这个问题的提示。 (另请参阅definition of object safety in the language reference。) -
@sven 我明白这一点。但是上面的例子是说只要所有的结构都有一个
read()方法,我们确实可以把它们放在一个集合中。测试代码运行良好,并按照您的预期分别返回 0,123。 -
我有点困惑。说“所有结构都有
read()方法”没有多大意义。两个不同特征的read()方法是完全不相关的。要问的重要问题是结构是否实现了特定的特征。您可以为对象安全的 trait 提供 trait 对象的集合,但不能为非对象安全的 trait 提供这样的集合。如果您的read()方法返回关联类型,则需要指定该类型才能创建 trait 对象——Box<dyn ReadEcs<T = f32>>应该是有效的。 -
您的约束直接相互矛盾(您承认这一点)。要找到解决方案,您需要解释约束的哪些部分可以是灵活的,或者退后一步从底层需求重新评估。