我目前正在尝试用 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())));
}