为所有迭代器实现特征

时间:2017-12-27 09:42:32

标签: iterator rust traits

我正在创建一种从迭代器中格式化数据的方法。为了允许链接,我试图通过泛型提供它作为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)
            })
    }
}

然后我在这里使用它:

#[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!()
    }
}

当我在.iter()之后但在.map()之后使用它时它会起作用,并说它没有实现。但是std::slice::Iterstd::iter::Map实现了Iterator<Item = T> + Clone,那么问题出在哪里?

先谢谢你的帮助。

1 个答案:

答案 0 :(得分:1)

您的问题的MCVE可以写成

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

以下假设你错了

  

std::iter::Map实施Iterator<Item = T> + Clone

Rust文档中std::iter::Map

Trait implementations部分包括

impl<I, F> Clone for Map<I, F> where
    F: Clone,
    I: Clone, 
当源迭代器Map和函数Clone的类型都实现I时,

F实现Clone

不幸的是,在当前稳定的Rust版本1.22.1中,闭包没有实现Clone。该功能在功能门clone_closures下的夜间Rust中可用。 Playground link

您也可以通过重写Clone来删除to_separated_string的要求

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