Как вывести подходящее время жизни для реализации, используя время жизни для структур и impl? - PullRequest
1 голос
/ 17 октября 2019

Как мне устранить эту ошибку? Что именно я говорю компилятору, когда я использую «анонимное время жизни» в impl?

struct LineHandlerInfo<'a> {
    label: &'a str,
    match_literal: &'a str,
    f: fn(&str) -> Option<&str>,
}

struct Game<'a> {
    handlers: Vec<LineHandlerInfo<'a>>,
}

impl Game<'_> {
    fn match_str<'a>(
        &'a mut self,
        label: &'a str,
        match_literal: &'a str,
        mut f: fn(&str) -> Option<&str>,
    ) {
        let mut lh = LineHandlerInfo {
            label,
            match_literal,
            f,
        };
        self.handlers.push(lh);
    }
}

fn main() {
    let mut g = Game {
        handlers: Vec::new(),
    };
    g.match_str("echo hello", "hello", |s| {
        println!("{}", s);
        None
    });
}

Когда я пытаюсь скомпилировать, я получаю следующую ошибку:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
  --> src/main.rs:18:22
   |
18 |         let mut lh = LineHandlerInfo {
   |                      ^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime 'a as defined on the method body at 12:18...
  --> src/main.rs:12:18
   |
12 |     fn match_str<'a>(
   |                  ^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:19:13
   |
19 |             label,
   |             ^^^^^
note: but, the lifetime must be valid for the lifetime '_ as defined on the impl at 11:11...
  --> src/main.rs:11:11
   |
11 | impl Game<'_> {
   |           ^^
   = note: ...so that the expression is assignable:
           expected LineHandlerInfo<'_>
              found LineHandlerInfo<'_>

Как мне устранить эту ошибку и что именно я сообщаю компилятору, когда я указываю время жизни на impl Game, когда у меня уже есть время жизни в структуре?

Ответы [ 2 ]

2 голосов
/ 30 октября 2019

Как мне разрешить эту ошибку и что именно я сообщаю компилятору, когда я указываю время жизни на impl Game, когда у меня уже есть время жизни на структуре?

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

Время жизни структур

Чтобы использовать время жизни в структуре, вы объявляете время жизни внутри <> рядом с именем структуры, которую вы объявляете, а затем ссылается на это время жизни в определении структуры. Важно отметить, что заявленное время жизни ограничено определением структуры - оно не имеет никакого значения снаружи.

Например (используя MRE, предоставленное @Shepmaster):

struct Game<'a> {
    handlers: Vec<&'a str>,
}

СтруктураGame содержит вектор ссылок на строки, и строки, на которые ссылаются, должны длиться как минимум столько же, сколько структура Game.

Impl Lifetimes

При использовании спецификатора времени жизни дляблок impl, вы объявляете время жизни внутри <> рядом с ключевым словом impl, после чего вы можете ссылаться на время жизни как в реализуемой структуре, так и внутри реализациисам по себе, например так:

impl<'b> Game<'b> {
    fn match_str(&mut self, label: &'b str) {
        self.handlers.push(label);
    }
}

Обратите внимание, что я использую здесь совершенно другое имя времени жизни ('b), чтобы проиллюстрировать, что объявление времени жизни в структуре не зависит от того, которое объявлено в блоке impl.

Разбивка:

impl<'b>

Это означает, что мы определяем реализацию для структуры, и в рамках этого определениядалее мы будем использовать время жизни 'b

 Game<'b> {

Это означает, что impl предназначен для структуры Game с временем жизни 'b - поэтому любые ссылки на self внутри этой реализации будут выполняться автоматическитакже имеют время жизни 'b.

fn match_str(&mut self, label: &'b str) {

Здесь мы определяем метод match_str, который принимает аргумент label. label - это фрагмент строки, который также имеет время жизни 'b - поэтому он должен длиться как минимум столько же, сколько self для вызова метода.

В исходном коде у вас было что-токак это:

impl Game<'_> {
    fn match_str<'a>(&mut self, label: &'a str) {
    ...
    }
}

Это сообщало компилятору:

  • , что вы запускаете новый блок impl, и на уровне impl не объявлено время жизни
  • что реализация предназначена для структуры Game;эта структура имеет параметр времени жизни, но нас это не волнует, и мы не собираемся связывать его с каким-либо элементом реализации
  • Мы определяем метод match_str, и мы объявляем время жизни 'a, на который мы можем ссылаться в остальной части сигнатуры функции
  • У нас есть аргумент label, который имеет время жизни a, но мы не связываем это время жизни с чем-либо еще

Дополнительная информация:

1 голос
/ 17 октября 2019

Как устранить эту ошибку?

Удалите общее время жизни из функции, укажите имя времени жизни в блоке impl вместо использования анонимного времени жизни, затемиспользуйте именованное время жизни в аргументах функции. Удалите время жизни из &self:

impl<'a> Game<'a> {
    fn match_str(&mut self, label: &'a str, match_literal: &'a str, f: fn(&str) -> Option<&str>) {
        self.handlers.push(LineHandlerInfo {
            label,
            match_literal,
            f,
        });
    }
}

См. Также:

Что именно я делаю, когда использую «анонимную жизнь» в impl?

Вы фактически заявляете: «Я знаю, что естьздесь жизнь, но мне все равно ». Однако это не так для вашего случая;Вы заботитесь о времени жизни, которое параметризует тип, потому что это то, что ваши переменные должны соответствовать.

См. также:

для структуры с указателем на функцию

Это не имеет ничего общего с указателями на функции. При возникновении проблем при программировании я рекомендую создать минимальный воспроизводимый пример , в котором убраны вещи, которые не устраняют ошибку. Это позволяет сосредоточиться именно на проблеме под рукой. Например, это воспроизводит ту же ошибку:

struct Game<'a> {
    handlers: Vec<&'a str>,
}

impl Game<'_> {
    fn match_str<'a>(&mut self, label: &'a str) {
        self.handlers.push(label);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...