[英]Why can't Rust infer the resulting type of Iterator::sum?
This code works:此代码有效:
fn main() {
let a: i32 = (1i32..10).sum();
let b = a.pow(2);
}
If I remove the i32
type from a
, then I get this error:如果我从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);
| ^^^^^^^^
I would have expected that Rust turns (1i32..10)
into an i32
iterator and then sum()
knows to return an i32
.我原以为 Rust 会将(1i32..10)
变成一个i32
迭代器,然后sum()
知道返回一个i32
。 What am I missing?我错过了什么?
The way sum
is defined, the return value is open-ended; sum
的定义方式,返回值是开放式的; more than one type can implement the trait Sum<i32>
.不止一种类型可以实现特征Sum<i32>
。 Here's an example where different types for a
are used, both of which compile:这是一个使用不同类型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);
}
Since both result types are possible, the type cannot be inferred and must be explicitly specified, either by a turbofish ( sum::<X>()
) or as the result of the expression ( let x: X = ...sum();
).由于两种结果类型都是可能的,因此无法推断类型,必须通过 turbofish ( sum::<X>()
) 或作为表达式的结果 ( let x: X = ...sum();
)。
and then
sum()
knows to return ani32
然后sum()
知道返回一个i32
This is the key missing point.这是关键的缺失点。 While the "input" type is already known (it has to be something that implements Iterator
in order for sum
to even be available), the "output" type is very flexible.虽然“输入”类型是已知的(它必须实现Iterator
才能使sum
可用),但“输出”类型非常灵活。
Check out Iterator::sum
:查看Iterator::sum
:
fn sum<S>(self) -> S
where
S: Sum<Self::Item>,
It returns a generic type S
which has to implement Sum
.它返回一个必须实现Sum
的泛型类型S
。 S
does not have to match Self::Item
. S
不必匹配Self::Item
。 Therefore, the compiler requires you to specify what type to sum into.因此,编译器要求您指定求和的类型。
Why is this useful?为什么这很有用? Check out these two sample implementations from the standard library:从标准库中查看这两个示例实现:
impl Sum<i8> for i8
impl<'a> Sum<&'a i8> for i8
That's right!这是正确的! You can sum up an iterator of u8
or an iterator of &u8
!您可以总结为u8
的迭代器或&u8
的迭代器! If we didn't have this, then this code wouldn't work:如果我们没有这个,那么这段代码将无法工作:
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 , we could accomplish this by having an associated type which would tie u8 -> u8
and &'a u8 -> u8
. 正如 bluss 指出的那样,我们可以通过关联u8 -> u8
和&'a u8 -> u8
的关联类型来实现这一点。
If we only had an associated type though, then the target sum type would always be fixed, and we'd lose flexibility.如果我们只有一个关联类型,那么目标和类型将始终是固定的,我们将失去灵活性。 See When is it appropriate to use an associated type versus a generic type?请参阅何时适合使用关联类型与泛型类型? for more details.更多细节。
As an example, we can also implement Sum<u8>
for our own types.例如,我们也可以为我们自己的类型实现Sum<u8>
。 Here, we sum up u8
s, but increase the size of the type we are summing, as it's likely the sum would exceed a u8
.在这里,我们总结了u8
s,但增加了我们正在总结的类型的大小,因为总和很可能会超过u8
。 This implementation is in addition to the existing implementations from the standard library:此实现是对标准库中现有实现的补充:
#[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);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.