2017-12-27 29 views
0

Ich erstelle eine Methode zum Formatieren von Daten aus einem Iterator. Damit Chaining, ich versuche, es als neue Methode der Iterator durch Generika zu bieten:Implementieren Sie die Eigenschaft für alle Iterator

trait ToSeparatedString { 
    fn to_separated_string(self, line_prefix: &str, separator: &str) -> String; 
} 

impl<T, I> ToSeparatedString for I 
where 
    T: Display, 
    I: Iterator<Item = T> + Clone, 
{ 
    fn to_separated_string(self, line_prefix: &str, separator: &str) -> String { 
     let len = self.clone().count(); 

     self.enumerate() 
      .map(|(i, line)| if i < len - 1 { 
       (line, separator) 
      } else { 
       (line, "") 
      }) 
      .fold::<String, _>("".to_owned(), |acc, (line, line_end)| { 
       format!("{}{}{}{}", acc, line_prefix, line, line_end) 
      }) 
    } 
} 

Dann ist es ich verwende hier:

#[derive(Debug)] 
pub struct TransactionDocumentBuilder<'a> { 
    /// Currency Id. 
    pub currency: &'a str, 
    /// Document timestamp. 
    pub blockstamp: Blockstamp, 
    /// Transaction locktime (in seconds ?) 
    pub locktime: u64, 
    /// List of issuers. 
    pub issuers: Vec<ed25519::PublicKey>, 
    /// List of inputs. 
    pub inputs: Vec<Input>, 
    /// List of outputs. 
    pub outputs: Vec<Output>, 
    /// Transaction comment. 
    pub comment: &'a str, 
} 

impl<'a> DocumentBuilder<TransactionDocument> for TransactionDocumentBuilder<'a> { 
    fn build_with_signature(self, signature: ed25519::Signature) -> TransactionDocument { 
     TransactionDocument { 
      document: GenericDocumentBuilder::new(10, "Transaction", self.currency) 
       .with("Blockstamp", &self.blockstamp.to_string()) 
       .with("Locktime", &self.locktime.to_string()) 
       .with("Issuers", &self.issuers.iter().to_separated_string("", "\n")) 
       .with("Inputs", &self.inputs.iter() 
        .map(|input| input.source) 
        .to_separated_string("", " ")) 
       // Iterate through each input unlocks 
       .with("Unlocks", &self.inputs.iter() 
        .enumerate() 
        .map(|(i, input)| { 
         input.unlocks.iter().to_separated_string(&i.to_string(), "\n") 
        }) 
        .to_separated_string("", "\n") 
       ) 
       // more fields 
       .build_with_signature(signature), 
     }; 

     unimplemented!() 
    } 

    fn build_and_sign(self, _private_key: &ed25519::PrivateKey) -> TransactionDocument { 
     unimplemented!() 
    } 
} 

Es ist funktioniert, wenn ich verwende es nach ein .iter(), aber nicht nach einem .map(), und sagt, es ist nicht implementiert. Aber std::slice::Iter und std::iter::Map implementiert Iterator<Item = T> + Clone, also wo ist das Problem?

Vielen Dank im Voraus für Sie Hilfe.

+0

Posting Umschreiben entfernen, um ein [Minimal, vollständig und prüfbare Beispiel (MCVE)] (https: // Stackoverflow. com/help/mcve), die Ihr Problem zeigt, würde Ihnen helfen, bessere Antworten zu erhalten. – red75prime

+0

Ich wusste es nicht. Ich werde es für zukünftige Fragen behalten. – Nanocryk

Antwort

1

MCVE für Ihre Frage als

vec![1,2,3].iter().map(|x| x).to_separated_string("", "") 

geschrieben werden konnten Sie

in der folgenden Annahme falsch waren std::iter::Map implementiert Iterator<Item = T> + Clone

Trait implementations Abschnitt für std::iter::Map in der Dokumentation Rust umfasst

impl<I, F> Clone for Map<I, F> where 
    F: Clone, 
    I: Clone, 

die Map ist implementiert Clone, wenn die Quelle Iterator I und die Art der Funktion F beide Clone implementieren.

Leider implementieren Verschlüsse nicht Clone in der aktuellen stabilen Rust-Version 1.22.1. Die Funktion ist im nächtlichen Rust unter Feature-Gate clone_closures verfügbar. Playground link

Sie können auch die Forderung nach Clone von to_separated_string wie die

fn to_separated_string(self, line_prefix: &str, separator: &str) -> String { 
    self.fold((true, "".to_string()), |(first, acc), line| { 
     (
      false, 
      format!(
       "{}{}{}{}", 
       acc, 
       if first { "" } else { separator }, 
       line_prefix, 
       line 
      ), 
     ) 
    }).1 
} 

Playground link

+0

große Antwort. Hinzufügen eines Verweises auf die [Kopieren/Klonen Schließungen RFC] (https://github.com/rust-lang/rfcs/blob/master/text/2132-copy-closures.md) –

+0

Ich dachte nicht an die Schließung . Danke für den funktionierenden Code, auch nicht für dieses Tupel-Setup. Sehr elegant, ich werde versuchen, diese Art von Dingen später zu benutzen. Kennst du einen Ort, um diese Art von Tricks zu finden? – Nanocryk

Verwandte Themen