我在 Rust 的类型推断中遇到了一个失败,我无法理解 - 正如大多数情况一样,我不知道这是否是编译器错误/不足,或者类型不应该可以推断,我只是不明白为什么。不幸的是,一个最低限度的工作示例需要付出一些努力。
num
包的功能,以便对具有自定义类型的向量进行数学计算。
我们从三个通用特征开始:
Producer
、AbsSub
和Power
。
use num_traits::{Pow, Signed};
pub trait Producer<B, const LEVEL: bool> {
/// Produce a single element
fn produce(&self) -> B;
}
pub trait AbsSub<A, B, const LEVEL: bool> {
// Vec isn't important here, we just need a generic return type
fn abs_sub(&self, other: &B) -> Vec<A>
where
A: Signed,
B: Producer<A, LEVEL>;
}
pub trait Power<A, B, C, const LEVEL: bool> {
fn power(&self, other: &C) -> Vec<A::Output>
where
A: Pow<B> + Copy,
C: Producer<B, LEVEL>;
}
当然,任何类型都可以生成自己,所以我们将继续添加一个全面的实现:
impl<A> Producer<A, false> for A // Note the `false` here
where
A: Copy,
{
fn produce(&self) -> A {
*self
}
}
现在,我们将定义一个包装类型,
Wrapper
,我们也想要生成它。如果我们在没有 Producer
的情况下定义 const bool
,我们就会不走运:我们的一揽子实现将意味着我们对同一类型实现了 Producer
两次。相反,我们将为 true
实现 Producer
版本的 Wrapper
:
#[derive(Debug, Clone, Copy)]
struct Wrapper<A>(A);
impl<A> Producer<A, true> for Wrapper<A>
where
A: Copy,
{
fn produce(&self) -> A {
self.0
}
}
最后,我们将添加
AbsSub
和 Power
以及 main
的实现:
impl<A, B, const LEVEL: bool> AbsSub<A, B, LEVEL> for Vec<A> {
fn abs_sub(&self, other: &B) -> Vec<A>
where
A: Signed,
B: Producer<A, LEVEL>,
{
self.iter().map(|v| v.abs_sub(&other.produce())).collect()
}
}
impl<A, B, C, const LEVEL: bool> Power<A, B, C, LEVEL> for Vec<A>
where
C: Producer<B, LEVEL>,
{
fn power(&self, other: &C) -> Vec<<A>::Output>
where
A: Pow<B> + Copy,
{
self.iter().map(|v| v.pow(other.produce())).collect()
}
}
fn main() {
let vec = vec![1, 2, 3];
// `AbsSub` compiles and works
let wrapped = Wrapper { 0: 2 };
let result = vec.abs_sub(&2);
assert_eq!(result, vec![0, 0, 1]);
let result = vec.abs_sub(&wrapped);
assert_eq!(result, vec![0, 0, 1]);
let wrapped = Wrapper { 0: 2u8 };
let result = vec.power(&2u8); // This compiles
let result = vec.power(&wrapped); // This doesn't
let result = Power::<_, _, _, true>::power(&vec, &wrapped); // But this does
}
坦率地说,这对我来说是令人难以置信的。但我不明白为什么推理适用于
wrapped
abs_sub
,但不适用于wrapped
power
。我收到大量编译器错误:
error[E0284]: type annotations needed
--> src/main.rs:75:22
|
75 | let result = vec.power(&wrapped);
| ^^^^^
|
= note: cannot satisfy `<i32 as Pow<_>>::Output == _`
help: try using a fully qualified path to specify the expected types
|
75 | let result = <Vec<i32> as Power<i32, B, Wrapper<u8>, LEVEL>>::power(&vec, &wrapped);
| ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ~
error[E0284]: type annotations needed
--> src/main.rs:75:22
|
75 | let result = vec.power(&wrapped);
| ^^^^^
|
note: required by a const generic parameter in `Power::power`
--> src/main.rs:7:26
|
7 | pub trait Power<A, B, C, const LEVEL: bool> {
| ^^^^^^^^^^^^^^^^^ required by this const generic parameter in `Power::power`
8 | fn power(&self, other: &C) -> Vec<A::Output>
| ----- required by a bound in this associated function
help: try using a fully qualified path to specify the expected types
|
75 | let result = <Vec<i32> as Power<i32, B, Wrapper<u8>, LEVEL>>::power(&vec, &wrapped);
| ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ~
error[E0283]: type annotations needed
--> src/main.rs:75:22
|
75 | let result = vec.power(&wrapped);
| ^^^^^
|
= note: multiple `impl`s satisfying `i32: Pow<_>` found in the `num_traits` crate:
- impl Pow<u16> for i32;
- impl Pow<u32> for i32;
- impl Pow<u8> for i32;
- impl Pow<usize> for i32;
note: required by a bound in `Power::power`
--> src/main.rs:10:12
|
8 | fn power(&self, other: &C) -> Vec<A::Output>
| ----- required by a bound in this associated function
9 | where
10 | A: Pow<B> + Copy,
| ^^^^^^ required by this bound in `Power::power`
help: try using a fully qualified path to specify the expected types
|
75 | let result = <Vec<i32> as Power<i32, B, Wrapper<u8>, LEVEL>>::power(&vec, &wrapped);
| ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ~
error[E0283]: type annotations needed
--> src/main.rs:75:22
|
75 | let result = vec.power(&wrapped);
| ^^^^^
|
note: multiple `impl`s satisfying `Wrapper<u8>: Producer<_, _>` found
--> src/main.rs:24:1
|
24 | / impl<A> Producer<A, false> for A
25 | | where
26 | | A: Copy,
| |____________^
...
33 | / impl<A> Producer<A, true> for Wrapper<A>
34 | | where
35 | | A: Copy,
| |____________^
note: required by a bound in `Power::power`
--> src/main.rs:11:12
|
8 | fn power(&self, other: &C) -> Vec<A::Output>
| ----- required by a bound in this associated function
...
11 | C: Producer<B, LEVEL>;
| ^^^^^^^^^^^^^^^^^^ required by this bound in `Power::power`
help: try using a fully qualified path to specify the expected types
|
75 | let result = <Vec<i32> as Power<i32, B, Wrapper<u8>, LEVEL>>::power(&vec, &wrapped);
| ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ~
error[E0284]: type annotations needed
--> src/main.rs:75:22
|
75 | let result = vec.power(&wrapped);
| ^^^^^
|
note: required for `Vec<i32>` to implement `Power<i32, _, Wrapper<u8>, _>`
--> src/main.rs:42:34
|
42 | impl<A, B, C, const LEVEL: bool> Power<A, B, C, LEVEL> for Vec<A>
| ----------------- ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^
| |
| unsatisfied trait bound introduced here
help: try using a fully qualified path to specify the expected types
|
75 | let result = <Vec<i32> as Power<i32, B, Wrapper<u8>, LEVEL>>::power(&vec, &wrapped);
| ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ~
如果有人能为这种行为提供任何解释,那就太棒了。我怀疑是否有“修复”,但我真的很想知道这是编译器不足还是真正的推理歧义。
让我们在推导时像编译器一样思考
vec.power(&wrapped);
跳过大部分方法查找,我们知道我们正在尝试匹配
Power
Vec<i32>
与 Wrapper<u8>
上的特征(这些扣除至少是
在错误输出中可用)。
A
是 i32
C
是 Wrapper<u8>
什么是
B
?唯一需要解决的是约束:
C: Producer<B, LEVEL>
和A: Pow<B>
不幸的是,这两个约束都不能根据
B
推导出奇异的 A
和
C
。两者都是“开集”:一个 C
可以实现多个 Producer
,而一个
A
可以实现多个Pow
。
Pow
肯定有多种实现 i32
-
错误输出显示了这一点。所以这绝对没有帮助。
然后
Producer
对于Wrapper<u8>
有两种实现:一种
LEVEL=false
的一揽子实施和一个通用实施
Wrapper<A>
与 LEVEL=true
。对你来说不幸的是,面对任何
歧义,编译器放弃并要求你澄清。它不
根据 LEVEL
进行任何探索性推论,看看是否有效。
现在,当您指定
<_, _, _, true>
时,这确实为规则提供了足够的帮助
我们的一揽子实施使得只剩下一个实施,并且
由此可以推导出B
。