2016-12-07 8 views
6

इस कोड काम करता है:जंग के परिणामस्वरूप प्रकार के 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।कॉम/क्यू/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> 

यह एक सामान्य प्रकार SSum लागू करने के लिए है जो देता है। 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

मुझे लगता है कि एक तार्किक कदम गायब है; सिर्फ इसलिए कि कई प्रकार एक ही चीज़ को जोड़ना चाहते हैं, इसका मतलब यह नहीं है कि एक और प्रकार पैरामीटर होना चाहिए। इसे एक संबंधित प्रकार 'और' एक i8 -> i8' और 'i8 -> i8' और इसी तरह से हल किया जा सकता है। – bluss

+0

@bluss एक बहुत अच्छा मुद्दा! – Shepmaster

+0

धन्यवाद। मेरा मतलब है, यह आपकी समस्या नहीं है, यह पुस्तकालय में है, लेकिन चूंकि यह जवाब इसे तर्कसंगत बनाने के लिए कदमों के माध्यम से जा रहा था, इसलिए मैं इसे इंगित करना चाहता था। मौजूद प्रकृति को तर्कसंगत बनाना शायद वैसे भी खुशी का मार्ग है ;-) – bluss

संबंधित मुद्दे

 संबंधित मुद्दे