假设我想编写一个通用函数,该函数接受一些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
}

但是,我现在不再能够在同一个函数中将两个浮点数相乘。实际上,似乎绑定(bind)的f64: Mul<K, Output = K>覆盖/隐藏(?)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>现在仅适用于<whatever>类型的K

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

我想做的一个不太抽象的示例:K可以是向量类型,也可以是标量类型,并且我希望能够以通用方式对其进行可交换标量乘法。

这里发生了什么?为什么我不能再乘b * b

更新:@Ömer-erden注意到它在明确指定f64: Mul<f64, Output = f64>时也有效。不幸的是,导入 alga crate时,该解决方法无法正常工作-请参阅updated playground link

我不确定海藻能做什么来打破已经很奇怪的行为。正如Ömer已经指出的那样,这似乎更多是类型检查器的错误或局限性,而不是藻类/其他方面的错误,因为理想情况下,对于任何内置类型,没有代码应该能够破坏impl Mul<f64, Output = f64>或类似代码的解析度。

最佳答案

这是一个约束,告诉您当K是正确的操作数时,您可以将f64K相乘,输出将是K。还告诉f64必须实现Mul<K, Output = K>

f64: Mul<K, Output = K>,

我还不知道,这可能是由于类型检查器或bug的功能有限而导致的,但是由于Mul<f64, Output = f64>的约束,在f64上实现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

关于generics - 一般在Rust中乘以不同类型的值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58657264/

10-10 18:34