为啥 Rust 不能推断出 Iterator::sum 的结果类型?
Posted
技术标签:
【中文标题】为啥 Rust 不能推断出 Iterator::sum 的结果类型?【英文标题】:Why can't Rust infer the resulting type of Iterator::sum?为什么 Rust 不能推断出 Iterator::sum 的结果类型? 【发布时间】:2017-04-22 09:03:42 【问题描述】:此代码有效:
fn main()
let a: i32 = (1i32..10).sum();
let b = a.pow(2);
如果我从a
中删除i32
类型,则会收到此错误:
rustc 1.13.0 (2c6933acc 2016-11-07)
error: the type of this value must be known in this context
--> <anon>:3:13
|
5 | let b = a.pow(2);
| ^^^^^^^^
Run the example
我原以为 Rust 会将 (1i32..10)
变成 i32
迭代器,然后 sum()
知道返回 i32
。我错过了什么?
【问题讨论】:
相关问题:***.com/q/40243061/1233251 【参考方案1】:sum
的方式定义,返回值是开放式的;不止一种类型可以实现特征Sum<i32>
。这是一个使用不同类型的a
的示例,两者都可以编译:
#[derive(Clone, Copy)]
struct Summer
s: isize,
impl Summer
fn pow(&self, p: isize)
println!("pow()", p);
impl std::iter::Sum<i32> for Summer
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = i32>,
let mut result = 0isize;
for v in iter
result += v as isize;
Summer s: result
fn main()
let a1: i32 = (1i32..10).sum();
let a2: Summer = (1i32..10).sum();
let b1 = a1.pow(2);
let b2 = a2.pow(2);
Playground
由于这两种结果类型都是可能的,因此无法推断类型,必须通过 turbofish (sum::<X>()
) 或作为表达式的结果 (let x: X = ...sum();
) 显式指定类型。
【讨论】:
【参考方案2】:然后
sum()
知道返回i32
这是关键的缺失点。虽然“输入”类型是已知的(它必须是实现 Iterator
的东西才能使 sum
可用),但“输出”类型非常灵活。
查看Iterator::sum
:
fn sum<S>(self) -> S
where
S: Sum<Self::Item>,
它返回一个泛型类型S
,它必须实现Sum
。 S
不必须匹配 Self::Item
。因此,编译器要求您指定什么
输入总和。
为什么这很有用?查看标准库中的这两个示例实现:
impl Sum<i8> for i8
impl<'a> Sum<&'a i8> for i8
没错!你可以总结一个u8
的迭代器或者一个&u8
的迭代器!如果我们没有这个,那么这段代码将无法工作:
fn main()
let a: i32 = (0..5).sum();
let b: i32 = [0, 1, 2, 3, 4].iter().sum();
assert_eq!(a, b);
As bluss points out,我们可以通过 关联类型 来实现这一点,该类型将绑定u8 -> u8
和&'a u8 -> u8
。
如果我们只有一个关联类型,那么目标总和类型将始终是固定的,我们将失去灵活性。详情请见When is it appropriate to use an associated type versus a generic type?。
例如,我们还可以为我们自己的类型实现Sum<u8>
。在这里,我们总结了u8
s,但增加了我们求和的类型的大小,因为总和可能会超过u8
。此实现是标准库中现有实现的补充:
#[derive(Debug, Copy, Clone)]
struct Points(i32);
impl std::iter::Sum<u8> for Points
fn sum<I>(iter: I) -> Points
where
I: Iterator<Item = u8>,
let mut pts = Points(0);
for v in iter
pts.0 += v as i32;
pts
fn main()
let total: Points = (0u8..42u8).sum();
println!(":?", total);
【讨论】:
我认为缺少一个合乎逻辑的步骤;仅仅因为多种类型想要对同一事物求和,并不意味着必须有另一个类型参数。它可以通过关联类型&'a i8 -> i8
和i8 -> i8
等来解决。
谢谢。我的意思是,这不是你的问题,它在图书馆里,但由于这个答案是通过一些步骤来合理化它,我想指出它。无论如何,合理化存在的 impl 可能是通往幸福的道路;-)以上是关于为啥 Rust 不能推断出 Iterator::sum 的结果类型?的主要内容,如果未能解决你的问题,请参考以下文章
为啥浏览器可以推断出某些省略的 HTML 元素,但不能推断出形成有效标记所需的所有省略的元素?