克隆一个存储闭包的结构 [英] Clone a struct storing a closure

查看:49
本文介绍了克隆一个存储闭包的结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试在 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆