3

这是我遇到的问题的一个非常简化的示例,但是给定一个trait Thingwhich implementsOrd和一个struct Objectwhich implements Thing,我有以下结构:

pub struct MyStruct<'a> {
    my_things: HashMap<i32, Vec<Box<dyn Thing + 'a>>>
}

impl<'a> MyStruct<'a> {
    pub fn new() -> MyStruct<'a> {
        MyStruct {
            my_things: HashMap::new()
        }
    }
    
    pub fn add_object(&mut self, key: i32, obj: Object) {
        if !self.my_things.contains_key(&key) {
            self.my_things.insert(key, Vec::new());
        }
        
        let new_thing: Box<dyn Thing> = Box::new(obj);
        let things = self.my_things.get_mut(&key).unwrap();
        
        things.push(new_thing);
        things.sort();
    }
}

它本质上需要一个键和一个Object,并使用给定的键将对象添加到 a HashMapof Vecs 中。我知道这不是执行此操作的最佳方法,但我想保持简单以进行说明。

编译器在调用时抱怨things.sort()以下错误:

error[E0308]: mismatched types
  --> src/main.rs:58:16
   |
58 |         things.sort();
   |                ^^^^ lifetime mismatch
   |
   = note: expected trait `Ord`
              found trait `Ord`
note: the lifetime `'a` as defined on the impl at 42:6...
  --> src/main.rs:42:6
   |
42 | impl<'a> MyStruct<'a> {
   |      ^^
   = note: ...does not necessarily outlive the static lifetime

游乐场链接

如果我在此示例中删除所有'a生命周期,则代码将编译。但对于我的实际用例,我需要允许非静态生命周期。

有人可以解释这里发生了什么吗?sort()真的需要Vec包含具有静态生命周期的项目吗?如果是,为什么?

有没有好的解决方法?

4

1 回答 1

6

您只Orddyn Thing + 'static. 'static如果您没有明确指定任何其他生命周期界限,则会推断生命周期界限。要Ord为非'static dyn Things 实现,您需要在您的实现中引入和使用通用生命周期参数,例如'a。更新编译示例:

use std::collections::HashMap;
use std::cmp;

pub trait Thing {
    fn priority(&self) -> i32;
}

impl<'a> PartialEq for dyn Thing + 'a { // 'a added here
    fn eq(&self, other: &Self) -> bool {
        self.priority() == other.priority()
    }
}

impl<'a> PartialOrd for dyn Thing + 'a { // 'a added here
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        self.priority().partial_cmp(&other.priority())
    }
}

impl<'a> Eq for dyn Thing + 'a {} // 'a added here

impl<'a> Ord for dyn Thing + 'a { // 'a added here
    fn cmp(&self, other: &Self) -> cmp::Ordering{
        self.priority().cmp(&other.priority())
    }
}

pub struct Object {
    priority: i32,
}

impl Thing for Object {
    fn priority(&self) -> i32 {
        self.priority
    }
}

pub struct MyStruct<'a> {
    my_things: HashMap<i32, Vec<Box<dyn Thing + 'a>>>
}

impl<'a> MyStruct<'a> {
    pub fn new() -> MyStruct<'a> {
        MyStruct {
            my_things: HashMap::new()
        }
    }
    
    pub fn add_object(&mut self, key: i32, obj: Object) {
        if !self.my_things.contains_key(&key) {
            self.my_things.insert(key, Vec::new());
        }
        
        let new_thing: Box<dyn Thing> = Box::new(obj);
        let things = self.my_things.get_mut(&key).unwrap();
        
        things.push(new_thing);
        things.sort();
    }
}

fn main() {
    let _test = MyStruct::new();
}

操场


Rust 参考的Lifetime Elision一章Default Trait Object Lifetimes部分(强调我的):

如果 trait 对象用作泛型类型的类型参数,则首先使用包含类型来尝试推断界限。

  • 如果包含类型存在唯一绑定,则这是默认绑定
  • 如果包含类型有多个边界,则必须指定显式边界

如果这些规则都不适用,则使用 trait 的边界:

  • 如果特征是用单个生命周期定义的,则使用该边界。
  • 如果 'static 用于任何生命周期限制,则使用 'static。
  • 如果特征没有生命周期界限,则生命周期在表达式中推断并且在表达式'static之外。
于 2021-02-06T22:18:15.197 回答