添加常量泛型时"Unconstrained generic constant"



如何添加const泛型?假设我有一个类型foo:

pub struct foo <const bar: i64> {
value: f64,
}

我想实现乘法,这样我可以把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`

现在,它建议的子句不是很有用,原因之一:静态大小的切片的长度参数必须是usize,但我们的值bazquux(及其和)是i64。我猜想编译器作者包含了这个特别的建议,因为const泛型的主要用例是在类型中嵌入数组大小。我已经在GitHub上打开了一个关于这个诊断的问题。

为什么这是必要的?

where子句根据一个或多个泛型参数或其衍生物必须满足的特征和生存期,指定了一些泛型代码元素的约束——函数、类型、trait,或者在本例中是实现。许多情况下都有等价的简写,但总体要求是约束是完全指定的。

在我们的例子中,表面上看起来这个实现适用于bazquux的任何组合,但由于整数溢出,情况并非如此;如果我们为两者提供相同符号的足够大的值,它们的和不能用i64表示。这意味着i64在加法下不闭合。

我们添加的约束要求这两个值的和在i64的可能值的集合中,间接地要求具有消耗它的类型。因此,为bazquux同时提供2^31是无效的,因为结果类型Foo<{baz + quux}>不存在,所以它不可能实现Sized特性。虽然这在技术上是一个比我们需要的更严格的约束(Sized是一个比简单存在的类型更强的要求),但所有存在的Foo<bar>都实现了Sized,所以在我们的例子中是一样的。另一方面,如果没有约束,则没有where子句(显式或简写)指定此约束。

相关内容

  • 没有找到相关文章

最新更新