我是 Rust 的新手,并且见过一些人们使用 Box 来允许将实现特定 Trait 的许多类型推送到 Vec 上的示例。当将 Trait 与泛型一起使用时,我遇到了一个问题。
error[E0038]: the trait `collision::collision_detection::Collidable` cannot be made into an object
--> src/collision/collision_detection.rs:19:5
|
19 | collidables: Vec<Box<Collidable<P, M>>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `collision::collision_detection::Collidable` cannot be made into an object
|
= note: method `get_ncollide_shape` has generic type parameters
error: aborting due to previous error
error: Could not compile `game_proto`.
To learn more, run the command again with --verbose.
Run Code Online (Sandbox Code Playgroud)
这是我的代码
extern crate ncollide;
extern crate nalgebra as na;
use self::ncollide::shape::Shape;
use self::ncollide::math::Point;
use self::ncollide::math::Isometry;
use self::na::Isometry2;
pub trait Collidable<P: Point, M> {
fn get_ncollide_shape<T: Shape<P, M>>(&self) -> Box<T>;
fn get_isometry(&self) -> Isometry2<f64>;
}
pub struct CollisionRegistry<P, M>
where
P: Point,
M: Isometry<P>,
{
collidables: Vec<Box<Collidable<P, M>>>,
}
impl<P: Point, M: Isometry<P>> CollisionRegistry<P, M> {
pub fn new() -> Self {
let objs: Vec<Box<Collidable<P, M>>> = Vec::new();
CollisionRegistry { collidables: objs }
}
pub fn register<D>(&mut self, obj: Box<D>)
where
D: Collidable<P, M>,
{
self.collidables.push(obj);
}
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试使用可碰撞对象作为异质游戏对象的列表,这将为我提供 ncollide 兼容的形状以反馈到碰撞检测引擎中。
编辑:为了消除一些混乱。我并不是试图构造并返回 Trait 的实例。我只是想创建一个 Vec,允许将 Collidable 特征的任何实例推到它上面。
Rust 是一种编译语言,因此当它编译代码时,它需要知道生成机器代码可能需要的所有信息。
当你说
trait MyTrait {
fn do_thing() -> Box<u32>;
}
struct Foo {
field: Box<MyTrait>
}
Run Code Online (Sandbox Code Playgroud)
你告诉Rust它将Foo包含一个box包含任何实现MyTrait. 通过装箱类型,编译器将删除该特征未涵盖的有关数据类型的任何其他数据。这些特征对象被实现为一组数据字段和一个函数表(称为vtable),其中包含特征公开的函数,因此可以调用它们。
当你改变时
fn do_thing() -> Box<u32>;
Run Code Online (Sandbox Code Playgroud)
到
fn do_thing<T>() -> Box<T>;
Run Code Online (Sandbox Code Playgroud)
它可能看起来很相似,但行为却有很大不同。我们来看一个普通函数的例子
fn do_thing<T>(val: T) { }
fn main() {
do_thing(true);
do_thing(45 as u32);
}
Run Code Online (Sandbox Code Playgroud)
编译器执行所谓的操作monomorphization,这意味着编译器中的代码本质上变成了
fn do_thing_bool(val: bool) { }
fn do_thing_num(val: u32) { }
fn main() {
do_thing_bool(true);
do_thing_num(45 as u32);
}
Run Code Online (Sandbox Code Playgroud)
需要意识到的关键一点是,你要求它为你的特质做同样的事情。问题是编译器无法做到这一点。上面的示例依赖于提前知道do_thing在一种情况下使用数字调用,在另一种情况下使用布尔值调用,并且它可以 100% 确定地知道这是该函数使用的唯一两种方式。
用你的代码
trait MyTrait {
fn do_thing<T>() -> Box<T>;
}
Run Code Online (Sandbox Code Playgroud)
编译器不知道do_thing将调用什么类型,因此它无法生成您需要调用的函数。为此,无论您将结构实现转换Collidable为装箱对象,它都必须知道每种可能的返回类型get_ncollide_shape,但这是不支持的。
其他链接:
| 归档时间: |
|
| 查看次数: |
1723 次 |
| 最近记录: |