gpt4 book ai didi

rust - 使用 Trait 作为 Vec 类型

转载 作者:行者123 更新时间:2023-11-29 08:06:12 25 4
gpt4 key购买 nike

我是 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.

这是我的代码

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);
}
}

我正在尝试使用可碰撞对象作为异构游戏对象的列表,这些对象会给我 ncollide 兼容的形状,以反馈给碰撞检测引擎。

编辑:澄清一些困惑。我不是在尝试构造和返回 Trait 的实例。我只是想创建一个 Vec,它允许将 Collidable 特征的任何实例推送到它上面。

最佳答案

Rust 是一种编译语言,因此当它编译您的代码时,它需要知道生成机器代码可能需要的所有信息。

当你说

trait MyTrait {
fn do_thing() -> Box<u32>;
}

struct Foo {
field: Box<MyTrait>
}

您告诉 Rust Foo 将包含一个 box,其中包含任何实现 MyTrait 的内容。通过对类型进行装箱,编译器将删除该特征未涵盖的有关数据类型的任何其他数据。这些trait objects被实现为一组数据字段和一个函数表(称为 vtable),其中包含特征公开的函数,因此可以调用它们。

当你改变的时候

fn do_thing() -> Box<u32>;

fn do_thing<T>() -> Box<T>;

它可能看起来很相似,但行为却大不相同。让我们以一个普通的函数为例

fn do_thing<T>(val: T) { }

fn main() {
do_thing(true);
do_thing(45 as u32);
}

编译器执行所谓的单态化,这意味着编译器中的代码本质上变成了

fn do_thing_bool(val: bool) { }
fn do_thing_num(val: u32) { }

fn main() {
do_thing_bool(true);
do_thing_num(45 as u32);
}

要意识到的关键是,您要求它为您的特质做同样的事情。问题是编译器做不到。上面的示例依赖于提前知道 do_thing 在一种情况下用数字调用,在另一种情况下用 bool 值调用,并且它可以 100% 确定这是函数唯一的两种方式用过。

用你的代码

trait MyTrait {
fn do_thing<T>() -> Box<T>;
}

编译器不知道 do_thing 将被调用的类型,因此它无法生成您需要调用的函数。为此,无论您将实现 Collidable 的结构转换为盒装对象,它都必须知道 get_ncollide_shape 可能具有的每种可能的返回类型,而这是不受支持的。

其他链接:

关于rust - 使用 Trait 作为 Vec 类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46065104/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com