2016-11-19 2 views
0

Ich habe eine Eigenschaft geschrieben, dass einige Methoden ähnlich denen von Vec angibt:Wie kann ich FromIterator automatisch implementieren?

pub trait Buffer { 
    type Item; 
    fn with_capacity(c: usize) -> Self; 
    fn push(&mut self, item: Self::Item); 
} 

Ich möchte implementieren FromIterator für alle Typen, die Buffer implementieren, wie folgt:

impl<T> iter::FromIterator<T::Item> for T 
    where T: Buffer 
{ 
    fn from_iter<I>(iter: I) -> Self 
     where I: IntoIterator<Item = T> 
    { 
     let mut iter = iter.into_iter(); 
     let (lower, _) = iter.size_hint(); 
     let ans = Self::with_capacity(lower); 
     while let Some(x) = iter.next() { 
      ans.push(x); 
     } 
     ans 
    } 
} 

der Won-Compiler Lassen Sie mich:

error[E0210]: type parameter `T` must be used as the type parameter 
for some local type (e.g. `MyStruct<T>`); only traits defined in the 
current crate can be implemented for a type parameter 

Ich glaube, ich verstehe die Fehlermeldung; Es hindert mich daran, Code zu schreiben, der nicht mit möglichen zukünftigen Änderungen der Standardbibliothek kompatibel ist.

Der einzige Weg um diesen Fehler scheint zu sein, FromIterator für jeden Typ separat zu implementieren, für den ich Buffer implementieren. Dies beinhaltet das Kopieren von genau demselben Code viele Male. Gibt es eine Möglichkeit, die gleiche Implementierung zwischen allen Buffer Typen zu teilen?

+1

* mit möglichen zukünftigen Änderungen an der Standardbibliothek * - nicht nur an der Standardbibliothek, sondern an jeder Bibliothek, mit der Ihr Code in der Zukunft verlinkt (oder verlinkt sein kann). – Shepmaster

Antwort

0

Sie können ein Merkmal nicht aus einer anderen Kiste für einen beliebigen Typ implementieren, nur für einen Typ aus Ihrer Kiste. Sie können jedoch die Implementierung einer Funktion bewegen und die Menge der duplizierten Code reduzieren:

fn buffer_from_iter<I, B>(iter: I) -> B 
    where I: IntoIterator<Item = B::Item>, 
      B: Buffer 
{ 
    let mut iter = iter.into_iter(); 
    let (lower, _) = iter.size_hint(); 
    let mut ans = B::with_capacity(lower); 
    while let Some(x) = iter.next() { 
     ans.push(x); 
    } 
    ans 
} 

struct S1; 
impl Buffer for S1 { 
    type Item = i32; 
    fn with_capacity(c: usize) -> Self { unimplemented!() } 
    fn push(&mut self, item: Self::Item) { unimplemented!() } 
} 

impl std::iter::FromIterator<<S1 as Buffer>::Item> for S1 { 
    fn from_iter<I>(iter: I) -> Self 
     where I: IntoIterator<Item = <S1 as Buffer>::Item> 
    { 
     buffer_from_iter(iter) 
    } 
} 

Diese Implementierung von FromIterator kann in ein Makro eingewickelt werden, um Code-Duplizierung zu reduzieren.

+0

Besser noch, Ihr 'buffer_from_iter' kann' Buffer :: from_iter' sein, um eine Typvariable und viele "as Buffer" -Klauseln zu entfernen. Ich habe so viel selbst gearbeitet. :-(Die Idee, ein Makro zu verwenden, ist gut; ich hätte nichts dagegen, gelegentlich "buffer_from_iter! (MyType)" zu schreiben. Ich werde eine Antwort akzeptieren, die zeigt, wie das geht. – apt1002

+0

Wie wäre es damit? (Lernen, wie ich vorankomme !) https://gist.github.com/apt1002/1b5139f0e0d4e700b5732e0ae44fe3fb – apt1002

Verwandte Themen