Метод, содержащий параметр закрытия, ожидает неправильный тип? - PullRequest
0 голосов
/ 27 апреля 2020

У меня есть структура, Parser, которая содержит transformer - функцию, используемую для изменения ее ParserState - и упомянутый ParserState.

#[derive(Clone)]
pub struct Parser<F> 
where
    F: Fn(ParserState) -> ParserState
{
    pub transformer: F,
    pub state: ParserState
}

#[derive(Debug, PartialEq, Clone)]
pub struct ParserState {
    pub target: String,
    pub index: usize,
    pub result: Vec<String>, // the container of eventual results from the parsing, with Some(result) or None. Should be a vetor
    pub error: bool,            // whether we've encountered an error; index -> 0, Some(err_msg)
    pub err_msg: Option<String> // Eventual error message
}

Определение метода .map() Я предположил, что мог бы просто использовать замыкание и ссылаться на собственное состояние синтаксического анализатора внутри него, передавая его в качестве аргумента этому замыканию. Это замыкание будет использоваться в качестве параметра метода .map().

impl<F> Parser<F>
where
    F: Fn(ParserState) -> ParserState 
{
    pub fn new(f: F) -> Self {
        // creating a new Parser just means deciding on which closure it applies
        Parser {
            transformer: f,
            state: ParserState {
                target: String::from(""),
                index: 0,
                result: vec![],
                error: false,
                err_msg: None
            }
        }
    }

    pub fn map<G>(&mut self, g: G) -> ()
    where
        G: Fn(ParserState) -> ParserState
    {
        self.state = g((self.state).clone())
    }

    pub fn run(mut self, corpus: String) -> Self {
        self.state.target = corpus;
        self.state = (self.transformer)(self.state);
        self
    }
}

Я использую это так:

fn main() {
    let haystack: String = String::from("Hello!Goodbye!");
    let needle = String::from("Hello!");
    let str_parser = Parser::new(str_parser(needle));
    let closure = |mut state: ParserState| state.index = 0;
    let result = str_parser.run(haystack);
    let result = result.map(closure);
    let adv = ParserState {
        target: "Hello!Goodbye!".to_string(),
        index: 0,
        result: vec!["Hello!".to_string()],
        error: false,
        err_msg: None
    };
    assert_eq!(adv, result.state);
}

Это не сработало. Я столкнулся с этой ошибкой:

error[E0271]: type mismatch resolving `<[closure@src/lib.rs:49:23: 49:63] as std::ops::FnOnce<(parse
rs::ParserState,)>>::Output == parsers::ParserState`
  --> src/lib.rs:51:29
   |
51 |         let result = result.map(closure);
   |                             ^^^ expected `()`, found struct `parsers::ParserState`

и не уверен, насколько FnOnce, о котором я не упомянул, имеет значение. Я также не понимаю, как .map() ожидает () в качестве аргумента, когда это метод Parser. Я чувствую себя немного не в своей тарелке.

Вот ссылка на соответствующую игровую площадку Rust

1 Ответ

2 голосов
/ 27 апреля 2020

Это замыкание возвращает () (то есть оно не возвращает значение):

let closure = |mut state: ParserState| state.index = 0;

Но F объявляется как возвращающее ParserState. Вам просто нужно заставить функцию возвращать значение, как и ожидалось.

let closure = |mut state: ParserState| {
    state.index = 0;
    state
};

и я не уверен, насколько FnOnce, о котором я не упомянул, уместно.

FnOnce - наиболее общая функциональная черта; все функции могут быть вызваны хотя бы один раз, поэтому все функции реализуют FnOnce, но могут не реализовывать Fn или FnMut. Я думаю, тот факт, что в сообщении об ошибке упоминается FnOnce, является просто артефактом порядка, в котором он пытается сопоставить типы.

...