添加const泛型时的“无约束泛型常量”
我将如何添加 const 泛型?假设我有一个 foo 类型:
pub struct foo <const bar: i64> {
value: f64,
}
我想实现 mul 以便我可以将 2 相乘foo。我想把它bar当作一个维度,所以foo<baz>{value: x} * foo<quux>{value: k} == foo<baz + quux>{value: x * k},如下:
impl<const baz: i64, const quux: i64> Mul<foo<quux>> for foo<baz> {
type Output = foo<{baz + quux}>;
fn mul(self, rhs: foo<quux>) -> Self::Output {
Self::Output {
value: self.value * rhs.value,
}
}
}
我收到一个错误,告诉我我需要{baz+quux}在输出类型的定义中添加一个 where 绑定。这究竟是什么意思,我该如何实施?我在 上找不到任何看似相关的信息where。
回答
解决方案
我在你的代码上有一个变化在这里工作:
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`
现在,它建议的子句不是很有用,原因之一是:静态大小切片的长度参数必须是 a usize,但我们的值baz和quux(及其总和)是i64。我想编译器作者包含了这个特定的建议,因为 const 泛型的主要用例是在类型中嵌入数组大小。我在 GitHub 上打开了一个关于此诊断的问题。
为什么这是必要的?
甲where一些通用的代码元素---一个功能,类型,性状,或在这种情况下,执行关于子句指定约束---基于所述性状和寿命的一个或多个通用参数,或它们的衍生物,必须满足。许多情况下有等效的简写,但总体要求是完全指定约束。
在我们的情况下,可能表面上看来,这实现工程的任意组合baz和quux,但这种情况并非如此,由于整数溢出; 如果我们为两者提供足够大的相同符号的值,则它们的总和不能用 表示i64。这意味着i64在加法下不是封闭的。
我们添加的约束要求两个值的总和在 an 的可能值集合中i64,间接地,通过需要消耗它的类型的东西。因此,对于这两个供给2 ^ 31baz和quux是无效的,因为所得到的类型Foo<{baz + quux}>不存在,所以它不可能实现的Sized性状。虽然这在技术上是比我们需要的更严格的约束(Sized比简单存在的类型更强的要求),所有Foo<bar>存在的都实现了Sized,所以在我们的例子中它是相同的。另一方面,在没有约束的情况下,没有where子句,明确的或简写的,指定这个约束。