Смущенный этим параметром и возвращаемый тип объявляются с разными временами жизни, но здесь возвращаются данные из `key` - PullRequest
0 голосов
/ 26 июня 2018
use std::collections::HashMap;

#[derive(Eq, Hash, PartialEq)]
struct Key<'a> {
    key: &'a str,
}

fn get<'m, 'k, 'kr>(map: &'m HashMap<Key, usize>, key: &'k Key<'kr>) -> Option<&'m usize> {
    map.get(key)
}

fn main() {
    let map: HashMap<Key, usize> = HashMap::new();
    get(&map, &Key { key: "foo" });
}

выдает мне следующую ошибку:

error[E0623]: lifetime mismatch
 --> src/main.rs:9:5
  |
8 | fn get<'m, 'k, 'kr>(map: &'m HashMap<Key, usize>, key: &'k Key<'kr>) -> Option<&'m usize> {
  |                                                            --------     -----------------
  |                                                            |
  |                                                            this parameter and the return type are declared with different lifetimes...
9 |     map.get(key)
  |     ^^^^^^^^^^^^ ...but data from `key` is returned here

Да, время жизни key отличается от времени жизни возвращаемого типа, но я не вижу, как " данные из key возвращаются сюда" ... Я вижу данные из map возвращаются с использованием ключа как ... ну, просто ключ, который больше не нужен после того, как возвращено значение.

IMO, get должен работать только для всех переданных 'k и 'kr. Время жизни возвращаемого значения должно совпадать с временем жизни map. Это то, что я пытался выразить, но, очевидно, мое мышление где-то не так ..

1 Ответ

0 голосов
/ 26 июня 2018

У вас есть две Key в вашей подписи, которые должны быть связаны, но вы не связываете их. Самое простое решение - дать им одинаковое время жизни:

fn get<'m, 'k>(map: &'m HashMap<Key<'k>, usize>, key: &Key<'k>) -> Option<&'m usize>
//         ^^                      ^^^^                   ^^^^

Ваш оригинальный код ближе к этому после пожизненного отбора:

fn get<'m, 'k, 'kr, 'x>(map: &'m HashMap<Key<'x>, usize>, key: &'k Key<'kr>) -> Option<&'m usize>

Но я собираюсь использовать эту форму вместо:

fn get<'m, 'k1, 'k2>(map: &'m HashMap<Key<'k1>, usize>, key: &Key<'k2>) -> Option<&'m usize>

HashMap::get имеет нетривиальную подпись:

pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
where
    K: Borrow<Q>,
    Q: Hash + Eq, 

Например, это позволяет вам искать в HashMap<String, V> с &String или &str.

Давайте перенесем это в наш код и выполним некоторую замену универсальных типов:

fn get<'m, 'k1, 'k2>(map: &'m HashMap<Key<'k1>, usize>, key: &Key<'k2>) -> Option<&'m usize> {
    fake_get(map, key)
}

fn fake_get<'m, 'k1, 'k2>(_: &'m HashMap<Key<'k1>, usize>, k: &Key<'k2>) -> Option<&'m usize>
where
    Key<'k1>: Borrow<Key<'k2>>,
    Key<'k2>: Hash + Eq,
{
    None
}

Мы можем удалить границу Hash + Eq, потому что знаем, что это тривиально. Мы также можем удалить оболочку HashMap:

fn get<'m, 'k1, 'k2>(map: &'m Key<'k1>, key: &Key<'k2>) -> Option<&'m usize> {
    fake_get(map, key)
}

fn fake_get<'m, 'k1, 'k2>(_m: &'m Key<'k1>, _k: &Key<'k2>) -> Option<&'m usize>
where
    Key<'k1>: Borrow<Key<'k2>>,
{
    None
}

Ошибка сводится к границе Borrow - можем ли мы позаимствовать Key с произвольным временем жизни у другого Key с другим произвольным временем жизни?

Единственный способ для этого быть правдой, если известно, что одна жизнь переживет другую. Это можно выразить:

fn get<'m, 'k1, 'k2: 'k1>(map: &'m HashMap<Key<'k1>, usize>, key: &Key<'k2>) -> Option<&'m usize>
but data from `key` is returned here

Не думаю, что в этом случае это большое сообщение об ошибке. Я думаю, что вполне вероятно, что это редкий случай, который не был исправлен с этим сообщением об ошибке. Хорошая новость в том, что теперь у вас есть небольшая копия, чтобы сообщить о проблеме:

use std::borrow::Borrow;

struct Key<'a>(&'a str);

fn get<'a, 'k1, 'k2>(k1: &'a Key<'k1>, k2: &Key<'k2>) -> &'a i32 {
    fake_get(k1, k2)
}

fn fake_get<'a, 'k1, 'k2>(_k1: &'a Key<'k1>, _k2: &Key<'k2>) -> &'a i32
where
    Key<'k1>: Borrow<Key<'k2>>,
{
    &42
}

fn main() {}

Смотри также:

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