From<&V> 特征约束的生命周期问题

Lifetime issue with From<&V> trait constraint

尽管所讨论的 V 实例已被拥有,但以下代码会产生以下生命周期错误。

use std::collections::hash_map::HashMap;
use std::cmp::Eq;
use std::hash::Hash;

trait Set<V> {
    fn set(&mut self, value: V) -> Option<V>;
}

impl<'a, K: Eq + Hash + From<&'a V>, V: 'a> Set<V> for HashMap<K, V> {
    fn set(&mut self, v: V) -> Option<V> {
        let k = K::from(&v);
        self.insert(k, v)
    }
}

由此产生的错误...

   |
9  | impl<'a, K: Eq + Hash + From<&'a V>, V: 'a> Set<V> for HashMap<K, V> {
   |      -- lifetime `'a` defined here
10 |     fn set(&mut self, v: V) -> Option<V> {
11 |         let k = K::from(&v);
   |                 --------^^-
   |                 |       |
   |                 |       borrowed value does not live long enough
   |                 argument requires that `v` is borrowed for `'a`
12 |         self.insert(k, v)
13 |     }
   |     - `v` dropped here while still borrowed

error[E0505]: cannot move out of `v` because it is borrowed
  --> src/lib.rs:12:24
   |
9  | impl<'a, K: Eq + Hash + From<&'a V>, V: 'a> Set<V> for HashMap<K, V> {
   |      -- lifetime `'a` defined here
10 |     fn set(&mut self, v: V) -> Option<V> {
11 |         let k = K::from(&v);
   |                 -----------
   |                 |       |
   |                 |       borrow of `v` occurs here
   |                 argument requires that `v` is borrowed for `'a`
12 |         self.insert(k, v)
   |                        ^ move out of `v` occurs here

使用 higher-rank trait bound 表示为 for<'a>:

impl<K: Eq + Hash + for<'a> From<&'a V>, V> Set<V> for HashMap<K, V> {
    fn set(&mut self, v: V) -> Option<V> {
        self.insert(K::from(&v), v)
    }
}

查看它在 playground 上的工作情况。

作为一个普通的泛型参数,生命周期 'a 由调用者决定,它比 set() 调用本身长。但是,v 的生命周期仅局限于函数体,这意味着用于调用 K::from() 的任何生命周期 'a 都可以比 V 中可能包含的内容更长寿。仅仅因为 v 是一个拥有的值并不意味着它没有与之关联的生命周期,毕竟它是通用的。编译器已经尽力了,但它的建议不是你想要的。

使用 for<'a> From<&'a V> 约束意味着 K::from() 调用将在 任何 生命周期内工作,包括 [=14= 的短函数局部生命周期].