对具有通用参数的特征进行动态分配

问题描述 投票:0回答:1

我有以下Rust Playground permalink

来自我的以下Ray Tracing in a Weekend

在实施材料时,我选择创建特征Material

[我的想法是,世界上的对象将具有material属性,并且在射线Hit上,Hit可以查看对象并按需索取材料。对于我的Normal特征(遵循类似的想法),这很好用。我通过动态调度实现了所有这些,尽管我认为我已经掌握了足够多的特性边界以静态方式完成它。

在链接的代码中,您看到第13行,我正在请求实现Normal的对象具有将返回Material的方法。这表明现在Normal不再有资格成为特征对象error[E0038]: the trait Normal cannot be made into an object

[如果我从this之类的问题中正确理解,似乎由于泛型是单态的,Rust运行时不会切实泄漏material的适当方法,因为表面上每种实现Normal的类型可能存在一个不同的方法]?这似乎并没有引起我的兴趣,似乎与Rust运行时处于同一位置,我现在可以看看我手头的Normal实现器,说Sphere并说我将查看Sphere的vtable。您能解释我在哪里错吗?

[从那里,我试图简单地与编译器抗争,然后转到静态调度。第17-21行

struct Hit<'a> {
    point: Vec3,
    distance: f32,
    object: &'a dyn Normal,
}

成为

struct Hit<'a, T: Normal> {
    point: Vec3,
    distance: f32,
    object: &'a T,
}

并且从那里开始,我试图在似乎没有尽头的情况下接一个洞接一个洞。

除了学习我目前的理解有哪些根本错误之外,我还可以做些其他的设计选择?

generics rust dispatch
1个回答
0
投票

放在与Rust运行时相同的位置,我可以看一下一下我手头的Normal实现器,说一下Sphere,说我要看一下Sphere的vtable

除了Rust运行时在这里无能为力。

实际上,Rust没有“执行代码的东西”的意义上的运行时。 Rust运行时仅执行设置和清除任务,但是只要控制流在main函数内部某个位置,您就可以自己运行(并且在no_std环境中,甚至不存在)。因此,必须通过将vtable指针放在数据指针旁边,将每个动态分派放入该类型中-有关更多详细信息,请参见this documentation

但是,正如您已经说过的那样,泛型是单态的,因此fn material的每个实现都不会有一个Normal:这些函数会有一个未知的,可能无限的族,每种实现Material的类型。请注意“未知,可能无限”位:由于您不能泄漏私有部分,因此如果Normal特性是公共的,则Material特性也必须是公共的-然后没有什么会阻止您的代码用户添加您的代码未知的Material的另一种实现,根本无法将其嵌入dyn Normal的vtable中。

这就是通用方法不是对象安全的原因。它们无法放入特征对象vtable,因为创建特征对象时我们并不了解它们。

© www.soinside.com 2019 - 2024. All rights reserved.