克隆一个存储闭包的结构 [英] Clone a struct storing a closure
问题描述
我目前正在尝试在 Rust 中实现一个简单的 Parser-Combinator 库.为此,我想要一个通用的 map
函数来转换解析器的结果.
问题是我不知道如何复制一个包含闭包的结构体.以下示例中的 Map
结构就是一个示例.它有一个 mapFunction
字段存储一个函数,它接收前一个解析器的结果并返回一个新的结果.Map
本身就是一个解析器,可以进一步与其他解析器结合.
但是,对于要组合的解析器,我需要它们是可复制的(绑定了 Clone
特征),但是我如何为 Map
提供这个?>
示例:(只有伪代码,很可能无法编译)
trait Parser{//由于`Map`,无法绑定: Clone".//每个解析器都需要有一个 `run` 函数,它将输入作为参数//并可选择产生一个结果和剩余的输入.fn run(&self, input: ~str) ->选项<(A, ~str)>}结构字符{字符:字符}impl Parser为字符{//如果第一个字符解析器返回 Some(char)fn run(&self, input: ~str) ->选项<(char, ~str)>{如果 input.len() >0 &&输入[0] == self.chr {一些((self.chr, input.slice(1, input.len())))} 别的 {没有任何}}}struct Map<'a, A, B, PA>{解析器:PA,mapFunction: 'a |结果:A|->乙,}impla,A,B,PA:解析器A解析器 B对于地图<'a,A,B,PA>{fn run(&self, input: ~str) ->选项<(B, ~str)>{...}}fn 主(){让解析器 = Char{ chr: 'a' };let result = parser.run(~"abc");//let mapParser = parser.map(|c: char| atoi(c));assert!(result == Some('a'));}
如果您引用闭包是可能的,因为您可以复制
引用.
克隆闭包一般是不可能的.但是,您可以创建一个包含函数使用的变量的结构类型,在其上派生 Clone
,然后自己在其上实现 Fn
.
引用闭包的例子:
//如果我们希望能够制作地图,需要调整解析器类型的大小.特征解析器:大小{//由于 `Map`,不能绑定 ":Clone".//每个解析器都需要有一个 `run` 函数,它将输入作为参数//并可选择产生一个结果和剩余的输入.fn run(&self, input: &str) ->选项<(A,字符串)>;fn map(self, f: &Fn(A) -> B) ->映射<A、B、自身>{地图 {解析器:自我,map_function: f,}}}结构字符{chr:字符,}impl Parser为字符{//现在找到第一个比 2014 年更复杂//字符串的字符.我不知道如何轻松返回子切片//跳过第一个字符.返回一个 `String` 是一种浪费的方式//在 Rust 中构建解析器.fn run(&self, input: &str) ->选项<(字符,字符串)>{如果 !input.is_empty() {让 mut chars = input.chars();首先: char = chars.next().unwrap();如果 input.len() >0 &&第一个 == self.chr {让休息: String = chars.collect();一些((self.chr,休息))} 别的 {没有任何}} 别的 {没有任何}}}struct Map<'a, A: 'a, B: 'a, PA>{解析器:PA,map_function: &'a Fn(A) ->乙,}impla,A,B,PA:解析器A解析器 B对于地图<'a,A,B,PA>{fn run(&self, input: &str) ->选项<(B,字符串)>{let (a, rest) = self.parser.run(input)?;一些(((self.map_function)(a),休息))}}fn 主(){让解析器 = Char { chr: '5' };让 result_1 = parser.run(&"567");让基数 = 10;让闭包 = |c: 字符|c.to_digit(base).unwrap();断言!(result_1 == Some(('5', "67".to_string())));让 map_parser = parser.map(&closure);让 result_2 = map_parser.run(&"567");assert!(result_2 == Some((5, "67".to_string())));}
I'm currently trying to implement a simple Parser-Combinator library in Rust. For that I would like to have a generic map
function to transform the result of a parser.
The problem is that I don't know how to copy a struct holding a closure. An example is the Map
struct in the following example. It has a mapFunction
field storing a function, which receives the result of the previous parser and returns a new result. Map
is itself a parser that can be further combined with other parsers.
However, for parsers to be combined I would need them to be copyable (having the Clone
trait bound), but how do I provide this for Map
?
Example: (Only pseudocode, will most likely not compile)
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'));
}
It's possible if you take a reference to the closure because you can Copy
references.
Cloning closures is not possible in general. However, you can make a struct type that contains the variables that the function uses, derive Clone
on it, and then implement Fn
on it yourself.
Example of a reference to a closure:
// 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())));
}
这篇关于克隆一个存储闭包的结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!