2016-12-07 2 views
6

Этот код работает:Почему Rust не может вывести результирующий тип Iterator :: sum?

fn main() { 
    let a: i32 = (1i32..10).sum(); 
    let b = a.pow(2); 
} 

Если удалить i32 тип из a, то я получаю эту ошибку:

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

я ожидал бы, что ржавчина превращается (1i32..10) в i32 итератор, а затем sum() знает, что возвращает i32. Что мне не хватает?

+0

Связанный вопрос: http: // stackoverflow.com/q/40243061/1233251 –

ответ

6

Путь 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

Так как возможны, очевидно, тип не может быть выведен.

5

and then sum() knows to return an i32

Это то место, где вы поступили не так. Проверьте 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.

Если у нас был только связанный тип, тогда тип целевой суммы всегда был бы исправлен, и мы потеряли бы гибкость. Например, мы можем также реализовать Sum для наших собственных типов.

Здесь мы подытожим 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); 
} 
+1

Я думаю, что логический шаг отсутствует; Просто потому, что несколько типов хотят суммировать одно и то же, не означает, что должен быть другой параметр типа. Его можно решить с помощью связанного типа '& 'a i8 -> i8' и' i8 -> i8' и т. Д. – bluss

+0

@bluss очень хороший момент! – Shepmaster

+0

Спасибо. Я имею в виду, это не ваша проблема, это в библиотеке, но поскольку этот ответ был своего рода шагом по его рационализации, я хотел бы указать на это. Рационализируя существо, которое существует, вероятно, путь к счастью в любом случае ;-) – bluss

 Смежные вопросы

  • Нет связанных вопросов^_^