2016-12-05 4 views
5

Я пытаюсь изучить Ржавчину, и, как и многие другие, я отправился писать итератор последовательности Фибоначчи для практики. Мой первый проход использовал u32 и работал отлично, поэтому я решил попробовать создать общую версию. Это мой результат:Как избежать чрезмерного клонирования в ржавчине?

use num::Integer; 
use std::ops::Add; 

pub struct Fibonacci<T: Integer + Add + Clone> { 
    nth: T, 
    n_plus_one_th: T, 
} 

impl<T: Integer + Add + Clone> Iterator for Fibonacci<T> { 
    type Item = T; 
    fn next(&mut self) -> Option<T> { 
     let temp = self.nth.clone(); 
     self.nth = self.n_plus_one_th.clone(); 
     self.n_plus_one_th = temp.clone() + self.n_plus_one_th.clone(); 
     Some(temp) 
    } 
} 

impl<T: Integer + Add + Clone> Fibonacci<T> { 
    pub fn new() -> Fibonacci<T> { 
     Fibonacci { 
      nth: T::one(), 
      n_plus_one_th: T::one(), 
     } 
    } 
} 

Я испытал это с u32 и num::BigUint, и она отлично работает. Тем не менее, меня беспокоит все клонирование в методе next. В частности, я не понимаю, зачем мне клонировать во время шага добавления.

Я подозреваю, что есть лучший способ написать это, используя некоторые из более продвинутых ссылочных понятий Руста, но пока я не понял этого.

ответ

7

Решение использовать пункт where следующим образом:

extern crate num; 

use num::One; 
use std::ops::Add; 

pub struct Fibonacci<T> { 
    nth: T, 
    n_plus_one_th: T, 
} 

impl<T> Fibonacci<T> 
    where T: One 
{ 
    pub fn new() -> Fibonacci<T> { 
     Fibonacci { 
      nth: T::one(), 
      n_plus_one_th: T::one(), 
     } 
    } 
} 

impl<T> Iterator for Fibonacci<T> 
    where for<'a> &'a T: Add<&'a T, Output = T> 
{ 
    type Item = T; 
    fn next(&mut self) -> Option<T> { 
     use std::mem::swap; 
     let mut temp = &self.nth + &self.n_plus_one_th; 
     swap(&mut self.nth, &mut temp); 
     swap(&mut self.n_plus_one_th, &mut self.nth); 
     Some(temp) 
    } 
} 

В частности, пункт for<'a> &'a T: Add<&'a T, Output=T> гласит «для любой жизни 'a, &'a T должны осуществлять Add с РИТ из &'a T и Output=T То есть. вы можете добавить два &T s, чтобы получить новый T.

При этом единственная оставшаяся проблема заключается в перетасовке значений вокруг, что может быть сделано с помощью swap.

Я также взял на себя смелость упростить ограничения в другом месте (вам нужно было только One, а не Integer).

+0

Одно быстрое наблюдение: я заметил, что вы не поместили никаких ограничений на структуру непосредственно, только на реализации. Это конвенция о ржавчине? –

+0

@MarkTozzi В основном это зависит от личных предпочтений. Вы можете повторять границы повсюду, если вы хотите сделать это более трудным для «неправильного использования» типа, но для примера это казалось излишним. –

+0

В том случае, если кто-то тоже задается вопросом: конструкция «где для» называется («Магия») «Ранжирование признаков более высокого ранга» (HRTB) и документируется здесь https://doc.rust-lang.org/nomicon/hrtb. HTML – Sebastian

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