解决方案
我对你的代码进行了修改,可以正常工作:
impl<const baz: i64, const quux: i64> Mul<Foo<quux>> for Foo<baz>
where Foo<{baz + quux}>: Sized {
type Output = Foo<{baz + quux}>;
fn mul(self, rhs: Foo<quux>) -> Self::Output {
Self::Output {
value: self.value * rhs.value,
}
}
}
我是如何到达那里的
我已经重现了您在没有添加的情况下收到的完整错误where
以下条款:
error: unconstrained generic constant
--> src/main.rs:11:5
|
11 | type Output = Foo<{baz + quux}>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: try adding a `where` bound using this expression: `where [u8; {baz + quux}]: Sized`
现在,它建议的子句不是很有用,原因之一是:静态大小的切片的长度参数必须是usize
,但我们的价值观baz
and quux
(及其总和)是i64
。我想编译器作者会包含该特定建议,因为 const 泛型的主要用例是将数组大小嵌入类型中。我有在 GitHub 上打开了一个问题 https://github.com/rust-lang/rust/issues/82509关于这个诊断。
为什么这是必要的?
A where
子句指定对某些通用代码元素(函数、类型、特征,或者在本例中为实现)的约束,该约束基于一个或多个通用参数或其派生必须满足的特征和生命周期。许多情况都有等效的简写,但总体要求是完全指定约束。
在我们的例子中,表面上看这个实现适用于任何组合baz
and quux
,但事实并非如此,由于整数溢出;如果我们为两者提供足够大的相同符号的值,则它们的总和不能表示为i64
。这意味着i64
在加法下不闭合。
我们添加的约束要求两个值的总和位于一个可能值的集合中i64
,间接地,通过要求消耗它的类型的东西。因此,为两者提供 2^31baz
and quux
无效,因为结果类型Foo<{baz + quux}>
不存在,所以它不可能实现Sized
特征。虽然这在技术上是比我们需要的更严格的限制(Sized
是比简单存在的类型更强的要求),所有Foo<bar>
存在实施Sized
,所以在我们的例子中是相同的。另一方面,如果没有约束,则where
子句(显式或简写)指定此约束。