试图通用时“特征的实现冲突”

yon*_*ong 6 types rust

背景:我正在使用该nalgebra库,我想创建一个表示多元正态分布的结构。M是矩阵的类型,例如Mat4<f64>

\n\n

我当前的尝试如下所示:

\n\n
use std::ops::Mul;\nuse std::marker::PhantomData;\nuse nalgebra::*;\n\n#[allow(non_snake_case)]\npub struct Multivar<N, V, M: SquareMat<N, V>> {\n    \xce\xbc: V,\n    \xce\xa3: M,\n    marker: PhantomData<N>\n}\n\nimpl<N, V, M> Mul<Multivar<N, V, M>> for M {\n    type Output = Multivar<N, V, M>;\n    fn mul(self, rhs: Multivar<N, V, M>) -> Multivar<N, V, M> {\n        Multivar {\n            \xce\xbc: self * rhs.\xce\xbc,\n            \xce\xa3: self * rhs.\xce\xa3 * transpose(&self)\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

然而,编译器抱怨:

\n\n

error: type parameter `M` must be used as the type parameter for some local type (e.g. `MyStruct<T>`); only traits defined in the current crate can be implemented for a type parameter

\n\n

\n\n

error: conflicting implementations for trait `core::ops::Mul`

\n\n

我不认为这应该是一个错误,因为我正在为我在这个模块中定义的结构定义一个实现。我应该如何解决这个问题?

\n

Vla*_*eev 5

您的代码的问题在于其中存在一致性冲突,并且很可能任何修复它的尝试都会导致新的一致性冲突。

Rust 中的一致性规则有些复杂,但是,它们基于一个原则:您可以为任意类型实现“您的”特征,也可以为“您的”类型实现任意特征。这听起来很简单,但当类型参数出现时,事情就变得复杂了——事实证明,有不止一种方法可以定义哪些类型是“你的”,哪些不是。

在这种特殊情况下,错误在于您直接为类型参数实现了外部特征:

impl<N, V, M> Mul<Multivar<N, V, M>> for M
Run Code Online (Sandbox Code Playgroud)

这直接违反了上述原则——你不能为你不拥有的类型实现你不拥有的特征(这样的实现称为“孤儿实现”)。这正是您的第一个错误的原因。

第二个错误让我认为您的Mul实现比此处提供的要多;无论如何,这也是违反一致性的。通常,当您有适用于特征的两个或多个不同实现的类型集的交集时,会导致此类错误:

use std::fmt;

trait X {}

impl X for i32 {}
impl<T: fmt::Display> X for T {}
Run Code Online (Sandbox Code Playgroud)

这里的实现是冲突的,因为它们都适用i32i32Implements fmt::Display

事实上,很难说出自己想要什么,因此也很难给出满意的答案。我试图解释上面这些错误的原因,希望它能帮助您正确编写特征实现。如果您有兴趣,可以在这篇有关孤立规则的博客文章中找到更多信息。