Жизненные проблемы при реализации функции, отображающей итератор с использованием HashMap - PullRequest
0 голосов
/ 26 января 2020

Я попытался реализовать функцию, которая отображает итератор, используя HashMap:

use std::collections::HashMap;
use std::hash::Hash;

/// Translates every element it gets using a map. In case the map does not help, it is mapped to
/// itself.
fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a + 'b
where
    S: Iterator<Item = T> + 'b,
    T: Copy + Eq + Hash,
{
    stream.map(|e: T| -> T { *map.get(&e).unwrap_or(&e) })
}

детская площадка

Я получаю сообщение об ошибке для этого кода :

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/lib.rs:11:16
   |
11 |     stream.map(|e: T| -> T { *map.get(&e).unwrap_or(&e) })
   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 6:14...
  --> src/lib.rs:6:14
   |
6  | fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a + 'b
   |              ^^
   = note: ...so that the types are compatible:
           expected &&std::collections::HashMap<T, T>
              found &&'a std::collections::HashMap<T, T>
note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 6:18...
  --> src/lib.rs:6:18
   |
6  | fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a + 'b
   |                  ^^
note: ...so that return value is valid for the call
  --> src/lib.rs:6:66
   |
6  | fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a + 'b
   |                                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Я не понял, что не так или как я могу это решить.

1 Ответ

1 голос
/ 26 января 2020

Я должен догадаться, поскольку вы не включили MCVE. Ваш код не компилируется с ошибками времени жизни на поверхности. Сигнатура функции, которую вы, вероятно, имели в виду:

fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a
where
    S: Iterator<Item = T> + 'b,
    T: Copy + Eq + Hash,
    'b: 'a, // Read: "'b outlives 'a"

Поскольку S может пережить ваше возвращаемое значение, и оно все равно будет действительным. Однако я не вижу никаких преимуществ этого подхода: более длинный срок службы всегда действителен вместо более короткого, вам не нужно явно указывать это. Просто используйте одно время жизни, как показано ниже.

fn translate<'a, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a
where
    S: Iterator<Item = T> + 'a,
    T: Copy + Eq + Hash,
{
    stream.map(move |e: T| -> T { *map.get(&e).unwrap_or(&e) })
}

Как видите, вам также не хватает ключевого слова move, которое абсолютно необходимо для вашего закрытия. В противном случае он может пережить вашу карту, которой владеет функция.

Тем не менее, эта функция довольно плотная. Если вы используете его только в одном месте, может, вообще не вводите его и избавляете от головной боли?

...