Бланкетный impl, HRTB и абстрактный тип возвращаемого значения «impl»: «параметр ожидаемого времени жизни» - PullRequest
1 голос
/ 25 марта 2019

Я запустил очень маленькую программу для работы с комбинаторами синтаксического анализа в Rust и быстро обнаружил странную ошибку:

trait Parser<T, E> {
    fn parse<'a>(&self, input: &'a [u8]) -> Result<(&'a [u8], T), E>;
}

impl<F, T, E> Parser<T, E> for F
where
    F: for<'a> Fn(&'a [u8]) -> Result<(&'a [u8], T), E>,
{
    fn parse<'a>(&self, input: &'a [u8]) -> Result<(&'a [u8], T), E> {
        (*self)(input)
    }
}

// why can't I write:
// fn byte(b: u8) -> impl Parser<u8, ()> {

// this works, and the blanket Parser impl picks it up correctly
fn byte(b: u8) -> impl for<'a> Fn(&'a [u8]) -> Result<(&'a [u8], u8), ()> {
    move |input: &[u8]| match input.first() {
        Some(x) if *x == b => Ok((&input[1..], *x)),
        _ => Err(()),
    }
}

fn main() {
    println!("{:?}", byte(b'c').parse(b"c123"));
}

Закомментированная подпись для byte (возвращающая impl Parser<u8, ()>) не компилируется с:

error[E0271]: type mismatch resolving `for<'a> <[closure@parser.rs:14:5: 19:6 b:_] as std::ops::FnOnce<(&'a [u8],)>>::Output == std::result::Result<(&'a [u8], u8), ()>`
  --> parser.rs:12:19
   |
12 | fn byte(b: u8) -> impl Parser<u8, ()> {
   |                   ^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'a, found concrete lifetime
   |
   = note: required because of the requirements on the impl of `Parser<u8, ()>` for `[closure@parser.rs:14:5: 19:6 b:_]`
   = note: the return type of a function must have a statically known size

Я не понимаю, почему ожидался связанный параметр времени жизни и какой конкретный срок жизни был найден.

На мой взгляд, возвращаемое замыкание имеет неописуемый тип. Этот тип реализует for <'a> Fn(&'a [u8]) -> Result<(&'a [u8], u8), ()> (и компилятор распознает это). Как следствие, он также должен быть реализован как Parser<u8, ()>, как я и думал.

1 Ответ

0 голосов
/ 16 мая 2019

На мой взгляд, возвращаемое закрытие имеет неописуемый тип.Этот тип реализует для <'a> Fn (&' a [u8]) -> Result <(& 'a [u8], u8), ()> (и компилятор распознает это).

Это только в том случае, если вы укажете его.

Рассмотрите сигнатуру функции без информации о времени жизни:

fn byte(b: u8) -> impl Fn(&[u8]) -> Result<(&[u8], u8), ()>

Что, если вы выписываете элитированные времена жизни, дает

fn byte<'a>(b: u8) -> impl Fn(&'a [u8]) -> Result<(&'a [u8], u8), ()>

Это не реализует for<'a> Fn ... высшего порядка - оно реализует черту Fn только для некоторого фиксированного 'a, установленного вызывающей стороной на byte.

Это конкретное время жизни, на которое жалуется компилятор - там, где он ожидает найти время жизни, связанное с for<...>, он вместо этого находит время жизни, которое уже описано.

...