如何在Rust中创建一个包含类型参数化函数的结构?



我是Rust的初学者,我试图创建一个解析器组合器库,以学习语言的技巧。在这个项目的早期,我就被困住了。我想有一个Parser结构体,用于保存用于解析数据的函数。这是我的尝试实现这个。

struct Parser<I, O> {
parse: impl Fn(&Vec<I>) -> Option<(&Vec<I>, O)>
}

不幸的是,正如编译器告诉我的那样,我不能使用"impl trait"。用这种方式表示。我尝试过的另一种方法是为函数本身的类型定义一个单独的类型变量,如下所示。

struct Parser<I, O, F> 
where
F: impl Fn(&Vec<I>) -> Option<(&Vec<I>, O)>
{
parse: F
}

然而,必须提供输入、输出和函数类型似乎是多余和不必要的,因为函数类型可以从输入和输出派生。此外,由于没有使用I或O,编译器会给我一个错误。

我还认为Parser可能必须是一个trait而不是一个结构体。然而,我不能真的把我的头围绕着看起来像什么,似乎你会遇到同样的问题,试图定义一个实现Parsertrait的结构体。

没有太多的上下文,但是我将尝试这样做:

struct Parser<I, O> {
parse: Box<dyn Fn(&Vec<I>) -> Option<(&Vec<I>, O)>>,
}
fn main() {
let parser = Parser {
parse: Box::new(|x| {
Some((x, x.iter().sum::<i32>()))
})
};
let v = vec![1, 2, 3, 4];
let result = (parser.parse)(&v).unwrap();
println!("{:?}", result);
}
如果需要更多的建议,我可以看看这里:在Rust中如何在结构中存储闭包?

我认为您所需要的是std::marker::PhantomData来沉默关于未使用泛型的错误。您还可以使用一些类型别名使代码更加DRY。(我已经用&[I]代替了&Vec<I>,因为后者是前者的严格超集。)

use std::marker::PhantomData;
type Input<'a,I> = &'a [I];
type Output<'a,I,O> = Option<(&'a [I], O)>;
struct Parser<I, O, F>
where
F: Fn(Input<'_,I>) -> Output<'_, I, O>,
{
parse: F,
_phantom: PhantomData<(I, O)>,
}
impl<I, O, F> Parser<I, O, F>
where
F: Fn(Input<'_, I>) -> Output<'_, I, O>,
{
fn new(parse: F) -> Self {
Self {
parse,
_phantom: PhantomData,
}
}
fn parse_it<'a>(&'a self, input: Input<'a, I>) -> Output<'a, I, O> {
(self.parse)(input)
}
}
fn main() {
let parser = Parser::new(|v: &[i32]| Some((v, v.iter().fold(0, |acc, x| acc + x))));
println!("{:?}", parser.parse_it(&[1, 2, 3]));
// ^ Some(([1, 2, 3], 6))
}

相关内容

  • 没有找到相关文章

最新更新