首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >实现dyn对象特性时的神秘生命周期问题

实现dyn对象特性时的神秘生命周期问题
EN

Stack Overflow用户
提问于 2019-01-23 14:14:18
回答 1查看 1.6K关注 0票数 20

考虑以下玩具示例:

代码语言:javascript
复制
use std::cmp::Ordering;

pub trait SimpleOrder {
    fn key(&self) -> u32;
}

impl PartialOrd for dyn SimpleOrder {
    fn partial_cmp(&self, other: &dyn SimpleOrder) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for dyn SimpleOrder {
    fn cmp(&self, other: &dyn SimpleOrder) -> Ordering {
        self.key().cmp(&other.key())
    }
}

impl PartialEq for dyn SimpleOrder {
    fn eq(&self, other: &dyn SimpleOrder) -> bool {
        self.key() == other.key()
    }
}

impl Eq for SimpleOrder {}

这不能编译。它声称在partial_cmp的实现中存在一个终身问题。

代码语言:javascript
复制
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
 --> src/main.rs:9:23
  |
9 |         Some(self.cmp(other))
  |                       ^^^^^
  |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 8:5...
 --> src/main.rs:8:5
  |
8 | /     fn partial_cmp(&self, other: &dyn SimpleOrder) -> Option<Ordering> {
9 | |         Some(self.cmp(other))
10| |     }
  | |_____^
note: ...so that the declared lifetime parameter bounds are satisfied
 --> src/main.rs:9:23
  |
9 |         Some(self.cmp(other))
  |                       ^^^^^
  = note: but, the lifetime must be valid for the static lifetime...
  = note: ...so that the types are compatible:
          expected std::cmp::Eq
             found std::cmp::Eq

我真的不明白这个错误。特别是“预期的std::cmp::Eq发现std::cmp::Eq__”令人费解。

如果我手动地内联调用,它就会编译得很好:

代码语言:javascript
复制
fn partial_cmp(&self, other: &dyn SimpleOrder) -> Option<Ordering> {
    Some(self.key().cmp(&other.key()))
}

这里发生了什么事?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-01-23 15:17:48

属性对象类型具有关联的生存期绑定,但可以省略。一个完整的特征对象类型是写dyn Trait + 'a (当在引用后面时,必须在它周围添加括号:&(dyn Trait + 'a))。

棘手的部分是,当一个生命周期界限被省略时,规则有点复杂

首先,我们有:

代码语言:javascript
复制
impl PartialOrd for dyn SimpleOrder {

在这里,编译器推断+ 'static。寿命参数从未在impl块上引入(从Rust 1.32.0开始)。

接下来,我们有:

代码语言:javascript
复制
    fn partial_cmp(&self, other: &dyn SimpleOrder) -> Option<Ordering> {

other的类型被推断为&'b (dyn SimpleOrder + 'b),其中'b是在partial_cmp上引入的隐式生存期参数。

代码语言:javascript
复制
    fn partial_cmp<'a, 'b>(&'a self, other: &'b (dyn SimpleOrder + 'b)) -> Option<Ordering> {

现在我们有了self的类型&'a (dyn SimpleOrder + 'static),而other的类型是&'b (dyn SimpleOrder + 'b)。有什么问题吗?

实际上,cmp没有给出任何错误,因为它的实现不要求两个特征对象的生存期相等。为什么partial_cmp会在意呢?

因为partial_cmp正在给Ord::cmp打电话。当键入检查对属性方法的调用时,编译器将检查来自该特性的签名。让我们回顾一下签名:

代码语言:javascript
复制
pub trait Ord: Eq + PartialOrd<Self> {
    fn cmp(&self, other: &Self) -> Ordering;

这种特性要求other的类型为Self。这意味着当partial_cmp调用cmp时,它尝试将一个&'b (dyn SimpleOrder + 'b)传递给一个期望&'b (dyn SimpleOrder + 'static)的参数,因为Selfdyn SimpleOrder + 'static。此转换无效('b不能转换为'static),因此编译器会产生错误。

那么,为什么在实现other时将&'b (dyn SimpleOrder + 'b)类型设置为&'b (dyn SimpleOrder + 'b)是有效的呢?因为&'b (dyn SimpleOrder + 'b)超型 of &'b (dyn SimpleOrder + 'static),而且Rust允许您在实现属性方法时用它的一个超级类型替换参数类型(它使该方法严格地更加通用,尽管它显然在类型检查中使用不多)。

为了使您的实现尽可能通用,您应该在impl上引入一个生存期参数:

代码语言:javascript
复制
use std::cmp::Ordering;

pub trait SimpleOrder {
    fn key(&self) -> u32;
}

impl<'a> PartialOrd for dyn SimpleOrder + 'a {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<'a> Ord for dyn SimpleOrder + 'a {
    fn cmp(&self, other: &Self) -> Ordering {
        self.key().cmp(&other.key())
    }
}

impl<'a> PartialEq for dyn SimpleOrder + 'a {
    fn eq(&self, other: &Self) -> bool {
        self.key() == other.key()
    }
}

impl<'a> Eq for dyn SimpleOrder + 'a {}
票数 21
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54329200

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档