2016-12-07 1 views
6

이 코드는 작동합니다왜 Rust는 Iterator :: sum의 결과 타입을 추론 할 수 없습니까?

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)를 켜지는지 예상 한 것 :

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

내가 a에서 i32 유형을 제거하면, 나는이 오류 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> 

을 그것은 Sum을 구현하는 제네릭 형식 S을 반환합니다. SSelf::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 초를 합산했지만 합계 유형이 증가합니다. 합계가 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

관련 문제