簡體   English   中英

如何在 Rust 中創建一個包含類型參數化函數的結構?

[英]How does one create a struct that holds a type parameterized function in Rust?

我是 Rust 的初學者,我正在嘗試創建一個 Parser Combinator 庫以學習該語言的原理。 在這個項目的早期,我被卡住了。 我想要一個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可能必須是一個特征而不是一個結構。 但是,我無法真正理解它的外觀,而且您似乎會在嘗試定義實現Parser特征的結構時遇到同樣的問題。

沒有很多上下文,但你我會嘗試這樣做:

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來消除有關未使用泛型的錯誤。 您還可以使用某些類型別名使代碼更加干燥。 (我已將&Vec<I>替換為&[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))
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM