Пожизненная ошибка при создании общего параметра - PullRequest
0 голосов
/ 31 марта 2020

Я свел свою проблему к следующему коду:

struct Struct<'a, 'b, T> {
    a: &'a T,
    b: &'b T,
}

trait Trait<'a, 'b, T> {
    fn a(&self) -> &'a T;
    fn b(&self) -> &'b T;
}

impl<'a, 'b, T> Trait<'a, 'b, T> for Struct<'a, 'b, T> {
    fn a(&self) -> &'a T {
        self.a
    }
    fn b(&self) -> &'b T {
        self.b
    }
}

struct Confused<T> {
    field: T,
}

impl<T> Confused<T> {
    fn foo<'a, 'b>(&'a self, param: &Struct<'a, 'b, T>) -> &'a T {
        param.b();
        param.a()
    }

    fn bar<'a, 'b, U: Trait<'a, 'b, T>>(&'a self, param: &U) -> &'a T {
        param.b();
        param.a()
    }
}

Функция foo в порядке, но когда я заменяю конкретный тип Struct<'a, 'b, T> на общий c тип U: Trait<'a, 'b, T>, Я получаю следующую ошибку:

error[E0309]: the parameter type `T` may not live long enough
  --> src/lib.rs:31:15
   |
24 | impl<T> Confused<T> {
   |      - help: consider adding an explicit lifetime bound `T: 'b`...
...
31 |         param.b();
   |               ^
   |
note: ...so that the reference type `&'b T` does not outlive the data it points at
  --> src/lib.rs:31:15
   |
31 |         param.b();
   |               ^

Предложение добавить границу T: 'b не имеет смысла для меня, поскольку 'b является параметром для bar(). Как я могу исправить bar(), чтобы принять любую реализацию Trait<'a, 'b, T> в качестве параметра?

1 Ответ

2 голосов
/ 31 марта 2020

Когда вы пишете обобщенный тип c, такой как:

struct Foo<'a, T> {
    a: &'a T,
}

Rust автоматически добавляет неявное ограничение типа T: 'a, потому что ваша ссылка на T не может жить дольше, чем T сам. Это автомат c, потому что ваш тип не будет работать без него.

Но когда вы делаете что-то вроде:

impl<T> Foo {
    fn bar<'a, 'b>() -> &'a T {/*...*/}
}

, есть автомат c T: 'a, но не T: 'b потому что нигде нет &'b T.

Решение состоит в том, чтобы добавить эти ограничения самостоятельно. В вашем коде это будет примерно так:

impl<T> Confused<T> {
    fn bar<'a, 'b, U: Trait<'a, 'b, T>>(&'a self, param: &U) -> &'a T
    where
        T: 'b, //<--- here!
    {
        param.b();
        param.a()
    }
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...