Ошибка «один тип более общий, чем другой» в Rust, в то время как типы идентичны

avatar
gurghet
9 августа 2021 в 06:36
160
1
4

У меня есть следующий код

use std::future::Future;
fn main() {
    handle(Test::my_func);
}

fn handle<Fut>(fun: for<'r> fn(&'r mut Test) -> Fut) -> bool
where
    Fut: Future<Output = ()> 
{
    true
}

struct Test {}

impl Test {
    pub async fn my_func<'r>(&'r mut self) -> () {
        ()
    }
}

Кроме того, вы можете запустить его онлайн на Rust Playground.

Появляется следующая ошибка:

error[E0308]: mismatched types
  --> src/main.rs:4:12
   |
4  |     handle(Test::my_func);
   |            ^^^^^^^^^^^^^ one type is more general than the other
...
17 |     pub async fn my_func<'r>(&'r mut self) -> () {
   |                                               -- checked the `Output` of this `async fn`, found opaque type
   |
   = note: while checking the return type of the `async fn`
   = note: expected fn pointer `for<'r> fn(&'r mut Test) -> impl Future`
              found fn pointer `for<'r> fn(&'r mut Test) -> impl Future`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

Теперь это действительно странно, потому что ясно говорит, что он получает то, что ожидает. Я не понимаю, какой тип более общий, чем какой. Я недостаточно понимаю время жизни, чтобы отлаживать этот код. Может ли кто-нибудь рассказать об этом поподробнее?

Источник
Ömer Erden
9 августа 2021 в 07:03
1

Введите сообщение об ошибке, которое может ввести в заблуждение: ваша асинхронная функция эквивалентна pub fn my_func<'r>(&'r mut self) -> impl Future<Output = ()> + 'r.

gurghet
9 августа 2021 в 07:04
0

Я нашел кое-что, что компилируется, но не уверен, что мне нужно: play.rust-lang.org/…

Ответы (1)

avatar
Ohad
9 августа 2021 в 07:18
6

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

16 |     pub async fn my_func<'r>(&'r mut self) -> () {
   |                                               ^^ checked the `Output` of this `async fn`, found opaque type
   = note: expected fn pointer `for<'r> fn(&'r mut Test) -> impl Future`
              found fn pointer `for<'r> fn(&'r mut Test) -> impl for<'r> Future`

Проще говоря, это означает, что вы ожидаете, что fun будет функцией, которая возвращает структуру, реализующую трейт Future, но с неявной привязкой + 'static, что означает, что структура не может иметь поля, которые активны только как пока 'r.

Однако Test::my_func действительно хочет сослаться на &mut 'r self, и из-за этого компилятор отклоняет программу.

Вы можете представить что-то вроде for<'r> fn(&'r mut Test) -> (impl Future + 'r), но в настоящее время это не то, что rustc принимает, и, насколько мне известно, нет никакого способа сделать это (без небезопасности или упаковки всего).

В зависимости от варианта использования вам может сойти с рук:

fn handle<'a, Fut>(fun: impl Fn(&'a mut Test) -> Fut) -> bool
where
    Fut: Future<Output = ()> + 'a,
{
    true
}

это работает, потому что нам требуется одно время жизни ('a), которое мы можем назвать для границы Fut: Future<Output = ()> + 'a, вместо любого времени жизни (for<'r> ..), которое мы не можем назвать в этой границе, но это намного более ограничительно.