【问题标题】:Clone a struct storing a closure [duplicate]克隆存储闭包的结构[重复]
【发布时间】:2014-03-22 22:27:37
【问题描述】:

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

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

但是,对于要组合的解析器,我需要它们是可复制的(具有 Clone 特征绑定),但我如何为 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'));
}

【问题讨论】:

  • 闭包不能被克隆。当您使用闭包时,我看不到任何摆脱困境的方法;看看你是否可以使用其他东西,例如裸函数。
  • 使用裸函数是我目前的解决方法。从客户的角度来看,我只是觉得它很难看。不过,感谢您的回答。

标签: rust rust-0.9


【解决方案1】:

如果你引用闭包是可能的,因为你可以Copy 引用。

一般情况下无法克隆闭包。但是,您可以创建一个包含函数使用的变量的结构类型,在其上派生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())));
}

【讨论】:

    猜你喜欢
    • 2013-08-21
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 2020-09-23
    • 1970-01-01
    • 1970-01-01
    • 2015-08-01
    • 1970-01-01
    相关资源
    最近更新 更多