微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么 Vec.sort() 似乎需要静态生命周期?

如何解决为什么 Vec.sort() 似乎需要静态生命周期?

这是我遇到的问题的一个大大简化的示例,但是给定一个实现 trait ThingOrd一个实现 struct ObjectThing,我具有以下结构:

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,并使用给定的键将对象添加HashMapVec 中。我知道这不是执行此操作的最佳方式,但我想让它更简单以进行说明。

编译器在调用 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

Playground link

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

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

有什么好的解决方法吗?

解决方法

您只为 Ord 实现了 dyn Thing + 'static。如果您没有明确指定任何其他生命周期界限,则会推断 'static 生命周期界限。要为非 Ord 'static 实现 dyn Thing,您需要引入和使用通用生命周期参数,例如'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();
}

playground


来自the Default Trait Object Lifetimes section of the Lifetime Elision chapter of the Rust Reference(强调我的):

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

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

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

  • 如果特征是用单个生命周期绑定定义的,则使用该绑定。
  • 如果 'static 用于任何生命周期绑定,则使用 'static。
  • 如果 trait 没有生命周期界限,那么生命周期是在表达式中推断出来的,并且在表达式之外是 'static

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。