Продолжая с Как мне написать комбинаторы для моих собственных анализаторов в Rust? , я наткнулся на этот вопрос, касающийся границ функций, которые потребляют и / или выдают функции / замыкания.
От эти слайды , я узнал, что для удобства потребителей, вы должны попытаться взять функции за FnOnce
и вернуть как Fn
, где это возможно. Это дает вызывающей стороне большую свободу, что передавать и что делать с возвращенной функцией.
В моем примере FnOnce
невозможно, потому что мне нужно вызывать эту функцию несколько раз. Пытаясь его скомпилировать, я нашел две возможности:
pub enum Parsed<'a, T> {
Some(T, &'a str),
None(&'a str),
}
impl<'a, T> Parsed<'a, T> {
pub fn unwrap(self) -> (T, &'a str) {
match self {
Parsed::Some(head, tail) => (head, &tail),
_ => panic!("Called unwrap on nothing."),
}
}
pub fn is_none(&self) -> bool {
match self {
Parsed::None(_) => true,
_ => false,
}
}
}
pub fn achar(character: char) -> impl Fn(&str) -> Parsed<char> {
move |input|
match input.chars().next() {
Some(c) if c == character => Parsed::Some(c, &input[1..]),
_ => Parsed::None(input),
}
}
pub fn some_v1<T>(parser: impl Fn(&str) -> Parsed<T>) -> impl Fn(&str) -> Parsed<Vec<T>> {
move |input| {
let mut re = Vec::new();
let mut pos = input;
loop {
match parser(pos) {
Parsed::Some(head, tail) => {
re.push(head);
pos = tail;
}
Parsed::None(_) => break,
}
}
Parsed::Some(re, pos)
}
}
pub fn some_v2<T>(mut parser: impl FnMut(&str) -> Parsed<T>) -> impl FnMut(&str) -> Parsed<Vec<T>> {
move |input| {
let mut re = Vec::new();
let mut pos = input;
loop {
match parser(pos) {
Parsed::Some(head, tail) => {
re.push(head);
pos = tail;
}
Parsed::None(_) => break,
}
}
Parsed::Some(re, pos)
}
}
#[test]
fn try_it() {
assert_eq!(some_v1(achar('#'))("##comment").unwrap(), (vec!['#', '#'], "comment"));
assert_eq!(some_v2(achar('#'))("##comment").unwrap(), (vec!['#', '#'], "comment"));
}
детская площадка
Теперь я не знаю, какую версию следует отдать предпочтение. Версия 1 использует Fn
, который является менее общим, но версия 2 нуждается в изменяемом параметре.
Какой из них более идиоматичен / должен использоваться и каково обоснование?
Обновление: Спасибо jplatte за предложение по первой версии. Я обновил код здесь, в этом случае я нахожу еще более интересным.