2016-01-06 16 views
6

मेरे पास Fibonacci संरचना है जिसे One, Zero, Add और Clone लागू करने वाले किसी भी चीज़ के लिए इटरेटर के रूप में उपयोग किया जा सकता है। यह सभी पूर्णांक प्रकारों के लिए बहुत अच्छा काम करता है।सामान्य प्रकार के दो संदर्भ जोड़ने के लिए एक विशेषता बाध्य कैसे लिखें?

मैं BigInteger प्रकार जो एक Vec के साथ लागू किया और पर clone() कॉल करने के लिए महंगे हैं कर रहे हैं के लिए इस struct उपयोग करना चाहते हैं। मैं Add का उपयोग T के दो संदर्भों पर करना चाहता हूं जो तब एक नया T (तब कोई क्लोनिंग नहीं) लौटाता है।

मुझे के जीवन मैं एक है कि हालांकि संकलित नहीं कर सकते हैं के लिए ...

कार्य:

extern crate num; 

use std::ops::Add; 
use std::mem; 
use num::traits::{One, Zero}; 

pub struct Fibonacci<T> { 
    curr: T, 
    next: T, 
} 

pub fn new<T: One + Zero>() -> Fibonacci<T> { 
    Fibonacci { 
     curr: T::zero(), 
     next: T::one(), 
    } 
} 

impl<'a, T: Clone + Add<T, Output = T>> Iterator for Fibonacci<T> { 
    type Item = T; 

    fn next(&mut self) -> Option<T> { 
     mem::swap(&mut self.next, &mut self.curr); 
     self.next = self.next.clone() + self.curr.clone(); 
     Some(self.curr.clone()) 
    } 
} 

#[test] 
fn test_fibonacci() { 
    let first_12 = new::<i64>().take(12).collect::<Vec<_>>(); 
    assert_eq!(vec![1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144], first_12); 
} 

वांछित:

extern crate num; 

use std::ops::Add; 
use std::mem; 
use num::traits::{One, Zero}; 

pub struct Fibonacci<T> { 
    curr: T, 
    next: T, 
} 

pub fn new<T: One + Zero>() -> Fibonacci<T> { 
    Fibonacci { 
     curr: T::zero(), 
     next: T::one(), 
    } 
} 

impl<'a, T: Clone + 'a> Iterator for Fibonacci<T> 
where 
    &'a T: Add<&'a T, Output = T>, 
{ 
    type Item = T; 

    fn next(&mut self) -> Option<T> { 
     mem::swap(&mut self.next, &mut self.curr); 
     self.next = &self.next + &self.curr; 
     Some(self.curr.clone()) 
    } 
} 

#[test] 
fn test_fibonacci() { 
    let first_12 = new::<i64>().take(12).collect::<Vec<_>>(); 
    assert_eq!(vec![1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144], first_12); 
} 

यह त्रुटि देता है

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements 
    --> src/main.rs:27:21 
    | 
27 |   self.next = &self.next + &self.curr; 
    |      ^^^^^^^^^^ 
    | 
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 25:5... 
    --> src/main.rs:25:5 
    | 
25 |/ fn next(&mut self) -> Option<T> { 
26 | |   mem::swap(&mut self.next, &mut self.curr); 
27 | |   self.next = &self.next + &self.curr; 
28 | |   Some(self.curr.clone()) 
29 | |  } 
    | |_____^ 
note: ...so that reference does not outlive borrowed content 
    --> src/main.rs:27:21 
    | 
27 |   self.next = &self.next + &self.curr; 
    |      ^^^^^^^^^^ 
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 19:1... 
    --> src/main.rs:19:1 
    | 
19 |/impl<'a, T: Clone + 'a> Iterator for Fibonacci<T> 
20 | | where 
21 | |  &'a T: Add<&'a T, Output = T>, 
22 | | { 
... | 
29 | |  } 
30 | | } 
    | |_^ 
note: ...so that types are compatible (expected std::ops::Add, found std::ops::Add<&'a T>) 
    --> src/main.rs:27:32 
    | 
27 |   self.next = &self.next + &self.curr; 
    |        ^

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements 
    --> src/main.rs:27:34 
    | 
27 |   self.next = &self.next + &self.curr; 
    |         ^^^^^^^^^^ 
    | 
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 25:5... 
    --> src/main.rs:25:5 
    | 
25 |/ fn next(&mut self) -> Option<T> { 
26 | |   mem::swap(&mut self.next, &mut self.curr); 
27 | |   self.next = &self.next + &self.curr; 
28 | |   Some(self.curr.clone()) 
29 | |  } 
    | |_____^ 
note: ...so that reference does not outlive borrowed content 
    --> src/main.rs:27:34 
    | 
27 |   self.next = &self.next + &self.curr; 
    |         ^^^^^^^^^^ 
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 19:1... 
    --> src/main.rs:19:1 
    | 
19 |/impl<'a, T: Clone + 'a> Iterator for Fibonacci<T> 
20 | | where 
21 | |  &'a T: Add<&'a T, Output = T>, 
22 | | { 
... | 
29 | |  } 
30 | | } 
    | |_^ 
note: ...so that reference does not outlive borrowed content 
    --> src/main.rs:27:34 
    | 
27 |   self.next = &self.next + &self.curr; 
    |         ^^^^^^^^^^ 
+0

आपको [std :: ops :: AddAssign] में रुचि हो सकती है (https://doc.rust-lang.org/std/ops/trait.AddAssign.html) जिसका आरएफसी अंतिम टिप्पणी अवधि में है: यह आपको "+ =" ऑपरेटर को अधिभारित करने देता है। यह कम से कम '.clone() 'कॉल के लिए कॉल से बचने की अनुमति देगा। –

+0

यह एक छोटा क्लोन होगा :) हालांकि मैं दोनों से छुटकारा नहीं पा सकता हूं। 12+ सप्ताह जब तक मुझे लगता है .. – dten

+0

वास्तव में दो कम क्लोन: 'self.next = self.next.clone() + self.curr.clone(); '' self.next + = और self द्वारा प्रतिस्थापित किया जाएगा। curr; '। –

उत्तर

5

आप बहुत करीबी थे:

impl<T> Iterator for Fibonacci<T> 
where 
    T: Clone, 
    for<'a> &'a T: Add<Output = T>, 
{ 
    type Item = T; 

    fn next(&mut self) -> Option<T> { 
     mem::swap(&mut self.next, &mut self.curr); 
     self.next = &self.next + &self.curr; 
     Some(self.curr.clone()) 
    } 
} 

आप एक प्रतिबंध यह है कि एक मनमाना जीवन भर का एक संदर्भ एक विशेषता को लागू करता है रखना चाहते हैं। इसे Higher Ranked Trait Bound (एचआरटीबी) कहा जाता है।

मैं यह समझ के रूप में, impl पर 'a जीवन रखने कि फोन करने वाले विधि के निर्धारित करने के लिए क्या जीवन होना चाहिए हो जाता है का मतलब है। चूंकि संदर्भ विधि के अंदर लिया जाता है, इसलिए कॉलर कभी भी यह नहीं देख सकता कि वह जीवनकाल क्या होगा।

+0

क्या आप जानते हैं कि अंतिम क्लोन को कैसे खत्म किया जाए? सहजता से मुझे लगता है कि वास्तविक संख्या को * इटरेटर * के बाहर * होना चाहिए, लेकिन मैं इसे काम नहीं कर सका। –

+0

@MaththieuM। मैं नहीं देखता कि क्लोन को खत्म करना कैसे संभव होगा, क्योंकि 'वर्तमान' मान संरचना द्वारा सहेजा गया है, लेकिन हम इसे इसे पुनरावर्तक से वापस करना चाहते हैं। मेरा अगला विचार 'वर्तमान' का संदर्भ वापस करना होगा, लेकिन इसके लिए जीवन भर को 'स्वयं' पर रखने की आवश्यकता होगी जो कि बिना चलने वाला है। क्या आप अपने "इटरेटर के बाहर" विचार पर विस्तार कर सकते हैं? – Shepmaster

+0

मेरा विचार राज्य को पकड़ने के लिए एक राज्य 'संरचना' बनाना था और फिर एक और इटरेटर 'स्ट्रक्चर' को पहले ('और mut') का संदर्भ देना था और इसे" अग्रिम "के रूप में बदलना था ताकि इटरेटर राज्य में संदर्भ वापस कर सके; लेकिन मैं अपने उधार को संरेखित करने का प्रबंधन नहीं कर सका। –

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