在 Rust 中一般乘以不同类型的值

Generically multiply values of different type in Rust

假设我想编写一个通用函数,它采用 K 类型的某些值并将其与 f64 可交换相乘。以下作品:

fn generic1<K>(a: K, b: f64) -> K
where
    K: Mul<f64, Output = K> + Add<K, Output = K> + Copy,
    f64: Mul<K, Output = K>,
{
     a * b + b * a
}

但是,我现在不能再在同一个函数中乘以两个浮点数。实际上,绑定 f64: Mul<K, Output = K> 似乎是 overriding/hiding (?) impl impl Mul<f64> for f64。这是一个例子:

fn generic2<K>(a: K, b: f64) -> K
where
    K: Mul<f64, Output = K> + Add<K, Output = K> + Add<f64, Output = K> + Copy,
    f64: Mul<K, Output = K>,
{
     a * b + b * a + b * b
}

这给出了以下编译器错误:

   |
16 |      a * b + b * a + b * b
   |                          ^ expected type parameter, found f64
   |
   = note: expected type `K`
              found type `f64`

(playground link),即 f64 * <whatever> 现在仅适用于类型为 K.

<whatever>

作为变通方法,我可以使用完全限定语法 <f64 as Mul<f64>>::mul(b, b),但那非常难看。感觉编译器应该能够看到它可以使用类型 f64 的输出,因此使用 f64 * f64 的实现而不是 f64 * K.

我想要做的事情的一个不太抽象的例子:K 可以是向量类型,也可以是标量类型,我希望能够以通用的方式用它进行交换标量乘法。

这是怎么回事?为什么我不能再乘 b * b?

更新:@Ömer-erden 注意到它在显式指定 f64: Mul<f64, Output = f64> 时也有效。不幸的是,在导入 alga crate - see the updated playground link.

时,解决方法失效了

我不太确定藻类会做什么来打破已经很奇怪的行为。正如 Ömer 已经指出的那样,这看起来更像是类型检查器的错误或限制,而不是 alga/whatever 中的错误,因为理想情况下没有代码应该能够破坏 impl Mul<f64, Output = f64> 或类似的解析任何内置类型。

这是一个约束条件,它告诉当 K 是右操作数时,您可以将 f64K 相乘,输出将是 K。还告诉 f64 必须执行 Mul<K, Output = K>

f64: Mul<K, Output = K>,

我还不知道,这可能是因为类型检查器的能力有限或错误,但由于约束 Mul<K, Output = K>.

如果您明确说明在您的情况下 Mul<f64, Output = f64> 的预期行为:

fn generic2<K>(a: K, b: f64) -> K
where
    K: Mul<f64, Output = K> + Add<K, Output = K> + Add<f64, Output = K> + Copy,
    f64: Mul<K, Output = K> + Mul<f64, Output = f64>,
{
    a * b + b * a + b * b
}

它将按预期工作。

Playground