简体   繁体   English

为什么 Rust 不能推断 Iterator::sum 的结果类型?

[英]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);
  |             ^^^^^^^^

Run the example 运行示例

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);
}

Playground 操场

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 an i32然后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.

相关问题 为什么Scala不能在此示例中推断出类型参数? - Why can't Scala infer the type parameter in this example? 为什么 typescript 不能推断 RxJs stream 中的元组返回类型? - Why can't typescript infer tuple return type in RxJs stream? 为什么scala无法在部分方法中推断出类型? - Why scala can't infer the type in a partial method? 如何将 TypeApplications 与 typeclass 方法一起使用,为什么 GHCi 会推断出我无法使用的类型? - How do I use TypeApplications with typeclass methods, and why does GHCi infer a type that I can't use? 当您将返回类型方法的 output 分配给变量时,为什么 Typescript 无法推断类型? - Why Typescript can't infer type when you assign a return typed method's output to a variable? Rust无法在没有注释的情况下推断类型 - Rust cannot infer type without annotation 为什么类型别名不能使用 Rust 中原始类型的关联常量? - Why can't a type alias use associated constants from the original type in Rust? 为什么 Rust 编译器可以在不同的行上推断出类型,但如果组合成一行则不能? - Why can the Rust compiler infer types on separated lines but not if combined into one line? Scala无法推断Java方法的类型参数 - Scala can't infer type arguments of Java method 无法推断通用tostring方法中的类型C# - Can't infer type in generic tostring method C#
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM