rust - 克隆存储闭包的结构

标签 rust rust-0.9

<分区>

我目前正在尝试用 Rust 实现一个简单的 Parser-Combinator 库。为此,我想要一个通用的 map 函数来转换解析器的结果。

问题是我不知道如何复制包含闭包的结构。一个示例是以下示例中的 Map 结构。它有一个 mapFunction 字段存储一个函数,该函数接收先前解析器的结果并返回一个新结果。 Map 本身就是一个解析器,可以与其他解析器进一步结合。

但是,对于要组合的解析器,我需要它们是可复制的(具有 Clone 特性绑定(bind)),但我如何为 Map 提供它?

示例:(仅伪代码,很可能无法编译)

trait Parser<A> { // Cannot have the ": Clone" bound because of `Map`.
    // Every parser needs to have a `run` function that takes the input as argument
    // and optionally produces a result and the remaining input.
    fn run(&self, input: ~str) -> Option<(A, ~str)>
}

struct Char {
    chr: char
}

impl Parser<char> for Char {
    // The char parser returns Some(char) if the first 
    fn run(&self, input: ~str) -> Option<(char, ~str)> {
        if input.len() > 0 && input[0] == self.chr {
            Some((self.chr, input.slice(1, input.len())))
        } else {
            None
        }
    }
}

struct Map<'a, A, B, PA> {
    parser: PA,
    mapFunction: 'a |result: A| -> B,
}

impl<'a, A, B, PA: Parser<A>> Parser<B> for Map<'a, A, B, PA> {
    fn run(&self, input: ~str) -> Option<(B, ~str)> {
        ...
    }
}

fn main() {
    let parser = Char{ chr: 'a' };
    let result = parser.run(~"abc");

    // let mapParser = parser.map(|c: char| atoi(c));

    assert!(result == Some('a'));
}

最佳答案

如果您引用闭包是可能的,因为您可以复制 引用。

克隆闭包一般是不可能的。但是,您可以制作一个包含函数使用的变量的结构类型,在其上派生 Clone,然后自己在其上实现 Fn

引用闭包的例子:

// The parser type needs to be sized if we want to be able to make maps.
trait Parser<A>: Sized {
    // Cannot have the ": Clone" bound because of `Map`.
    // Every parser needs to have a `run` function that takes the input as argument
    // and optionally produces a result and the remaining input.
    fn run(&self, input: &str) -> Option<(A, String)>;

    fn map<B>(self, f: &Fn(A) -> B) -> Map<A, B, Self> {
        Map {
            parser: self,
            map_function: f,
        }
    }
}

struct Char {
    chr: char,
}

impl Parser<char> for Char {
    // These days it is more complicated than in 2014 to find the first
    // character of a string. I don't know how to easily return the subslice
    // that skips the first character. Returning a `String` is a wasteful way
    // to structure a parser in Rust.
    fn run(&self, input: &str) -> Option<(char, String)> {
        if !input.is_empty() {
            let mut chars = input.chars();
            let first: char = chars.next().unwrap();
            if input.len() > 0 && first == self.chr {
                let rest: String = chars.collect();
                Some((self.chr, rest))
            } else {
                None
            }
        } else {
            None
        }
    }
}

struct Map<'a, A: 'a, B: 'a, PA> {
    parser: PA,
    map_function: &'a Fn(A) -> B,
}

impl<'a, A, B, PA: Parser<A>> Parser<B> for Map<'a, A, B, PA> {
    fn run(&self, input: &str) -> Option<(B, String)> {
        let (a, rest) = self.parser.run(input)?;
        Some(((self.map_function)(a), rest))
    }
}

fn main() {
    let parser = Char { chr: '5' };
    let result_1 = parser.run(&"567");

    let base = 10;
    let closure = |c: char| c.to_digit(base).unwrap();

    assert!(result_1 == Some(('5', "67".to_string())));

    let map_parser = parser.map(&closure);
    let result_2 = map_parser.run(&"567");
    assert!(result_2 == Some((5, "67".to_string())));
}

关于rust - 克隆存储闭包的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21933892/

相关文章:

Rust 0.9——读取文件?

rust - 通过共享框 ptr 访问时如何使我的结构字段可变?

string - 在 Rust 中将字符串转换为大写的最简单方法是什么?

使用rust :终身问题,需要帮助

gcc - 交叉编译的二进制文件未在RPI上运行,我可以正确编译吗?

rust - 我如何从图像::ImageBuffer到actix_web::HttpResponse

rust - 如何实现Into trait而不使用 `as usize`将所有输入转换为usize?

string - 如何在 Rust 中删除文本文件的第一行?