Руст функция подписей и переживаний - PullRequest
0 голосов
/ 18 апреля 2020

Чтобы выучить Rust, я пишу библиотеку синтаксических анализаторов. Теперь у меня есть проблема, которая охватывает сложный тип сечения и владение. У меня есть некоторые функции строительных блоков, которые я хотел бы использовать отдельно:

pub fn achar(character: char) -> impl Fn(&str) -> Option<char> {
    move |input| match input.chars().next() {
        Some(c) if c == character => Some(c),
        _ => None,
    }
}

pub fn alternatives<'a, T>(
    alts: &'a [impl Fn(&'a str) -> Option<T>],
) -> impl Fn(&'a str) -> Option<T> {
    move |input| {
        for alt in alts.iter() {
            let tried = alt(input);
            if tried.is_none() {
                continue;
            }
            return tried;
        }

        None
    }
}

pub fn one_of<'a>(allowed: &'a str) -> impl Fn(&'a str) -> Option<char> {
    let v = allowed.chars().map(achar).collect::<Vec<_>>();
    alternatives(&v)
}

Использование будет выглядеть следующим образом:

fn main() {
    println!("{:?}", achar('f')("foo"));
    println!("{:?}", alternatives(vec![achar('f'), achar('b')])("foo"));
    println!("{:?}", one_of("foo")("foo"));
}

Вот так я получаю следующую ошибку:

   = note:   expected type `for<'r> fn(&'r str) -> std::option::Option<char> {any_char}`
           found reference `&impl for<'r> std::ops::Fn<(&'r str,)>`

Я бы сказал, что quote реализует Fn(&str), не так ли? Как я могу заставить это работать?


Как только это будет решено, следующая проблема находится у двери:

33 |     alternatives(&v)
   |     ^^^^^^^^^^^^^--^
   |     |            |
   |     |            `v` is borrowed here
   |     returns a value referencing data owned by the current function

Конечно, встраивание не решает проблему. Я понятия не имею, как можно go атаковать это.

Детская площадка доступна здесь.

1 Ответ

1 голос
/ 18 апреля 2020

Здесь происходит несколько вещей:

pub fn alternatives<'a, T>(
    alts: &'a [impl Fn(&'a str) -> Option<T>],
) -> impl Fn(&'a str) -> Option<T> {
    move |input| {
        ...
    }
}

Выше сказано, что alternatives требует, чтобы все элементы в срезе alts были одного типа, и что этот тип реализует Fn(&'a str) -> Option<T>. Однако в вызове let escaping = alternatives(&vec![any_char, &quote, &backslash]); (или даже просто vec![any_char, &quote, &backslash];) элементы имеют разные типы (один тип any_char, следующий тип quote и т. Д.). С другой стороны, vec![achar('f'), achar('b')] работает, поскольку все элементы имеют тип achar.

То есть, даже если все элементы реализуют Fn(&str)->Option, они не совсем одного типа.

Относительно следующей ошибки:

pub fn one_of<'a>(allowed: &'a str) -> impl Fn(&'a str) -> Option<char> {
    let v = allowed.chars().map(achar).collect::<Vec<_>>();
    alternatives(&v)
}

Здесь вы возвращаете alternatives(&v), который занимает v. Но v выходит из области видимости в конце one_of, что означает, что результат alternatives будет относиться к чему-то, что было уничтожено, поэтому ржавчина запрещает это.

Теперь, что мы можем сделать в отношении типов, принятых alternatives?

  • alternatives может принимать коробочные функции. Это, однако, влечет за собой некоторые накладные расходы времени выполнения, но позволило бы динамически изменять число альтернатив c во время выполнения.
  • alternatives может принимать указатели на функции. Это, однако, запретило бы (захват среды) замыкания.
  • alternatives может принимать 2 функции, и более двух функций может быть предоставлено через макрос. Это в основном исправит количество альтернатив во время компиляции, но не потребует дополнительных затрат времени выполнения.

Что мы можем сделать с проблемой времени жизни в one_of?

  • This на самом деле это также может считаться проблемой в alternatives, так как alternatives, возможно, должен принимать некоторые функции в качестве аргументов и сохранять их так, чтобы вызывающей стороне не нужно было беспокоиться о проблемах времени жизни.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...