有什么方法可以对泛型类型设置复杂的条件和约束吗



以伪示例的形式:

trait A {}
trait B {}
trait C {}
struct D<T, X>
where
if T: A 
then X: is not B
else if X: B
then T: C
{}

我已经找到了一些绕过这一点的方法,但我想用语言功能来实现这一点。

更多解释

在我的项目中,一个小的光线跟踪器,我有一个顶点类型,它有一个位置和一个法线。我有另一个顶点类型,有一个位置,一个法线和一个纹理坐标。

我也有一些材质类型,可以使用特定的顶点类型。

我想对一些同时使用顶点和材质的函数进行约束:

fn do_something<V, M>(/* some arguments */) 
-> /* some returned value */ 
where 
if V: VertexWithTextureCoordinate 
then M: MaterialWithTexture 
else if V: SimpleVertex
then M: SimpleMaterial,
{
}

这是我面临的最简单的情况。

这并不容易。首先:Rust中还不存在负特征界(表示特征Foo)。有一些RFC,但AFAIK并没有在不久的将来实施类似的具体计划。然而,专业化可以让你模拟负面的特质界限。

Rust的类型系统是图灵完备的,但据我所知,如果不使用专门化和负特征界,你想要的是不可能的,这两者都是不实现/不稳定的。

你所要求的是一个相当普遍的情况;有一些具体的情况是可能的。如果你有这个结构D,并且想向它添加需要这些特征边界的方法,你只需要写两个impl块:

impl<T, X> D<T, X>
where
T: A,
X: NotB, // assume `NotB` is just another trait
{   
// ...
}
impl<T, X> D<T, X>
where 
T: C,
X: B,
{
// ...
}

如果你仔细想想,你无论如何都必须写两个实现:当TA时,你可以在T的对象上使用A的方法,当TC时,你也可以在T的对象上用C的方法,但你不能只告诉编译器"AC"。

特定问题的解决方案

在你的情况下,我会创建另一个特征,它表示顶点和材质的组合,可以很好地协同工作。类似于:

trait VertexMaterialPair {
// ...
}
impl<V, M> VertexMaterialPair for (V, M) 
where
V: VertexWithTextureCoordinate, 
M: MaterialWithTexture,
{ /* ... */ }
impl<V, M> VertexMaterialPair for (V, M) 
where
V: SimpleVertex, 
M: SimpleMaterial, 
{ /* ... */ }

正如您所看到的,我实现了顶点和材质的一对(元组)的特性。因此,您的函数看起来像:

fn do_something<V, M>(/* some arguments */) -> /* ... */ 
where
(V, M): VertexMaterialPair,
{ /* ... */ }

这应该相当有效;然而,这可能不是光线跟踪器的最佳解决方案。。。

最新更新