generics - 使用泛型参数对特征进行 Rust 动态调度

标签 generics rust dispatch

我有以下
Rust Playground permalink

来自我的关注 Ray Tracing in a Weekend .

在实现 Material 时,我选择创建一个特征 Material .

我的想法是世界上的物体会有 material属性和光线 Hit Hit可以查看对象并按需索要 Material 。这适用于我的 Normal遵循类似想法的特质。我用动态调度实现了这一切,尽管我认为我已经掌握了足够的能力,也可以通过 trait bound 静态地完成它。

在链接的代码中,您会看到第 13 行,我要求那些实现 Normal有一个方法会返回 Material .这表明现在 Normal不再有资格成为特征对象 error[E0038]: the trait正常 cannot be made into an object
如果我从 this 等问题中正确理解似乎由于泛型是单态化的,Rust 运行时不可能泄露material 的适当方法。鉴于实现 Normal 的每种类型表面上可能有一个不同的类型?这对我来说并不完全正确,因为看起来,放在与 Rust 运行时相同的位置,我将能够查看 Normal我手头的实现者,比如说Sphere并说我会查看Sphere的虚表。你能解释一下我在哪里错了吗?

从那里开始,我尝试简单地与编译器抗争并进行静态调度。
第 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,
}

从那里开始,我不得不尝试一个接一个地堵住一个又一个洞,似乎看不到尽头。

除了了解我目前的理解存在根本性错误之外,我还可以做哪些不同的设计选择?

最佳答案

我可能遗漏了一些东西,但我认为你可以——至少从我所看到的情况来看——进一步走你的路。

我认为您可以更改此功能:

fn material<T: Material>(&self) -> T;

就目前而言,它说:任何Normal提供功能material调用者可以在其中指定 Material该函数将返回。

但是(我认为)您要声明的是:任何 Normal有一个可以由调用者请求的 Material 。但是来电者无权口述任何Material那将被退回。要将其转换为代码,您可以声明:
fn material(&self) -> &dyn Material;

这表明 material返回 Material (作为特征对象)。

然后,Sphere可以实现Normal :
impl<'a> Normal for Sphere<'a> {
    fn normal(&self, point: &Vec3) -> Ray {
        Ray::new(point, &(point - &self.center))
    }
    fn material(&self) -> &dyn Material {
        self.material
    }
}

Link to playground.

关于generics - 使用泛型参数对特征进行 Rust 动态调度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61420414/

相关文章:

swift - 在 Apple 的 Swift 中实现通用接口(interface)

Java 本土泛型示例

c++ - 在 C 中从 Rust 读取指针

c# - C# 中派生类的动态调度

iOS Swift4 如何协调 T.Type 和类型(:) to pass dynamic class type as function parameter?

ios - 使用 Swift 泛型创建新的 NSManagedObjects

rust - 所有 T、&T、&mut T、[T]、&[T]、*mut T 的通用实现

generics - 我如何为另一个泛型类型的特征绑定(bind)表达类型参数的特征绑定(bind)?

python - Dispatch 未正确路由内部队列请求

ios - 用 2 个 block 排队 GCD