2016-12-10 25 views
6

Jestem stosunkowo nowy w Rust i staram się dowiedzieć o iteratorach. Specyficznym problemem, nad którym pracuję, jest iterator, który wytwarza liczby trójkątne (liczby trójkątów to 1, 3, 6, 10, 15, gdzie 1 = 1, 3 = 1 + 2, 6 = 1 + 2 + 3 itd.). Mam podstawy tego stworzone, pokazany tutaj:Czy możliwe jest zaimplementowanie niestandardowego Iterator :: sum w Rust?

pub struct Triangle { 
    cur: u32, 
    n: u32, 
    m: u32, 
} 

impl Iterator for Triangle { 
    type Item = u32; 

    fn next(&mut self) -> Option<u32> { 
     if self.n == self.m { 
      return None; 
     } 
     self.n = self.n + 1; 
     self.cur = self.cur + self.n; 

     Some(self.cur) 
    } 
} 

Szybkie runnable przykładem jest

let t = Triangle { cur: 0, n: 0, m: 10 }; 
let s: u32 = t.sum(); 
println!("{}", s); // prints 220 

Czy to możliwe, aby utworzyć niestandardową funkcję sumowania dla iteracyjnej, która zwraca typ u32. Miałem nadzieję, że będę mógł to zrobić z domyślnymi funkcjami iteratora i sumy i nie będę musiał wykonywać swojej własnej specjalistycznej funkcji.

miałem spojrzenie na to, i to, czego oczekiwałem, aby móc robić to

impl Sum<u32> for u32 { 
    fn sum<I>(iter: I) -> Self where I: Triangle { 
     let nsum = (self.n * (self.n + 1) * (self.n + 2))/6; 
     let msum = (self.m * (self.m + 1) * (self.m + 2))/6; 
     msum - nsum 
    } 
} 

ale to nie działa. Błąd, który mam z tym jest

error[E0404]: `Triangle` is not a trait 
    --> src/sequences.rs:61:41 
    | 
61 |  fn sum<I>(iter: I) -> Self where I: Triangle { 
    |           ^^^^^^^^ not a trait 

mogę zmienić go z Triangle do Iterator jak chce, ale które pozwalają mi dostępu do wartości Triangle struct m i n. Jeśli ktokolwiek mógłby mi powiedzieć, jak to zrobić, lub jeśli to niemożliwe, byłoby wspaniale. Wiem, że mógłbym napisać własną funkcję o nazwie coś innego, jak my_sum(), ale miałem nadzieję, że będę w stanie to zrobić w kontekście iteratora.

+1

I wyprodukować [MCVE] - "Num" nie jest cechą jako część standardowej rdzy, więc skąd wiemy, co potrafi? – Shepmaster

+0

Być może [jak mogę wprowadzić cechę, której nie posiadam dla typu, którego nie posiadam?] (Http://stackoverflow.com/q/25413201/155423) wyjaśni wszystko, co musisz wiedzieć? – Shepmaster

+0

@Shepmaster Myślę, że tak naprawdę nie chodzi o to, ale o zapewnienie wydajnej implementacji O (1) dla iteratora 'Triangle'. Wyczuwam, że przesłonięcie 'Iterator :: sum()' jest rozwiązaniem ... może. –

Odpowiedz

4

Nie można specjalizować istniejącej implementacji Sum, ale można specjalizować Iterator::sum w iteratorze! Jest to nieco trudne, ponieważ jego typ powrotu ma charakter ogólny.

use std::iter::{self, Sum}; 

impl Iterator for Triangle { 
    // existing members are unchanged 

    fn sum<S>(self) -> S where S: Sum<Self::Item> { 
     let nsum = (self.n * (self.n + 1) * (self.n + 2))/6; 
     let msum = (self.m * (self.m + 1) * (self.m + 2))/6; 
     S::sum(iter::once(msum - nsum)) 
    } 
} 

Nie możemy powrócić stałą typu (takie jak u32), jako że nie będzie respektować umowy określonej przez cechy Iterator. Wszystko, co wiemy na temat typu zwrotu S, to implementacja Sum<Self::Item>. Sum ma jedną metodę, sum, która zwraca Self, dzięki czemu możemy jej użyć do wygenerowania wartości typu S. Metoda oczekuje iteratora; podajemy go jako "iterator, który daje dokładnie jeden element". Ponieważ iterator będzie iterować określoną liczbę razy, możemy oczekiwać, że sum wykona określoną liczbę operacji.

Kiedy skompilować program w trybie zwolnienia i S jest u32 cała sum wezwanie jest zoptymalizowany daleko, a funkcja zwraca msum - nsum bezpośrednio.

+0

Ah, byłem tak blisko, ale nie mogłem wymyślić, jak przejść z 'T' do' S'. To całkiem fajne rozwiązanie! – Shepmaster