【问题标题】:Why can't I implement Deref for a specific lifetime?为什么我不能在特定的生命周期内实现 Deref?
【发布时间】:2021-09-09 07:00:14
【问题描述】:
use std::ops::{Deref};
use std::sync::{MutexGuard};

pub struct MutexGuardRef<'a, T> {
    mutex_guard: MutexGuard<'a, Option<Box<T>>>,
}

impl<'a, T> Deref for MutexGuardRef<'a, T> {
    type Target = Option<T>;

    fn deref(&'a self) -> &'a Self::Target {
        &self.mutex_guard.deref().as_ref().map(|x|*x)
    }
}

这给出了:

   = note: expected fn pointer `fn(&MutexGuardRef<'a, T>) -> &Option<T>`
              found fn pointer `fn(&'a MutexGuardRef<'a, T>) -> &'a Option<T>`

为什么我不能在特定生命周期内实现特征?为什么一定要一辈子?

【问题讨论】:

    标签: rust traits lifetime


    【解决方案1】:

    您的代码有两个问题需要解决。

    终身

    为什么我不能在特定的生命周期内实现特征?为什么必须 一辈子?

    在特定生命周期内实现特征没有问题,如impl&lt;'a, T&gt; Deref for MutexGuardRef&lt;'a, T&gt;。事实上,这是正确的做法。实现deref 方法时会出现编译器错误。

    我认为这里的混淆是由于对类型的生命周期界限的误解造成的,例如MutexGuardRef&lt;'a, T&gt; 中的'a'a 并不意味着MutexGuardRef&lt;'a, T&gt; 类型的每个值都存在于'a 期间;相反,这意味着 type 本身以'a 为界,这意味着 每个 value 最多存在 /em> 在'a 的持续时间内。我们将此称为限制 1

    另一方面,当您写下&amp;'a selfself: &amp;'a MutexGuardRef&lt;'a, T&gt; 的缩写)时,您是在说引用self 指向的*self一个'a 期间有效;换句话说,它是一个,它在'a 的持续时间内存在至少,我们将其称为限制 2.

    我希望这个解释能让事情变得更清楚——限制 1 是必要的,因为它是类型的固有属性;但是,限制 2 并不是我们要寻找的,因为取消引用 MutexGuardRef 值并不要求它像 Mutex 一样长。

    当我们从 deref 的实现中删除两个出现的 'a 时,我们得到

    fn deref(&self) -> &Self::Target
    

    简称

    fn deref(self: &MutexGuardRef<'a, T>) -> &Self::Target
    

    限制 1 被保留,而限制 2 被解除。因此编译器很满意...

    类型

    ...除了它向我们打招呼另一个错误:

    error[E0308]: mismatched types
      --> src/lib.rs:12:9
       |
    8  | impl<'a, T> Deref for MutexGuardRef<'a, T> {
       |          - this type parameter
    ...
    12 |         &self.mutex_guard.deref().as_ref().map(|x|*x)
       |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found struct `Box`
       |
       = note: expected reference `&Option<T>`
                  found reference `&Option<Box<T>>`
    

    揭示不同类型的问题。

    &amp;Self::Target,代表&amp;Option&lt;T&gt;,是对已经存在Option&lt;T&gt; 的引用。我们只有一个Mutex&lt;Option&lt;Box&lt;T&gt;&gt;&gt;——没有Option&lt;T&gt;可以指向。

    理想情况下,我们希望deref 返回一个Option&lt;&amp;T&gt;,它指向包裹在互斥锁中的最里面的T(如果有)。然而,Deref trait 规定返回类型为&amp;Self::Target,所以我们最好的调用是返回&amp;Option&lt;Box&lt;T&gt;&gt;

    结果:

    use std::{ops::Deref, sync::MutexGuard};
    
    pub struct MutexGuardRef<'a, T> {
        mutex_guard: MutexGuard<'a, Option<Box<T>>>,
    }
    
    impl<'a, T> Deref for MutexGuardRef<'a, T> {
        type Target = Option<Box<T>>;
    
        fn deref(&self) -> &Self::Target {
            &*self.mutex_guard
        }
    }
    

    (playground)

    【讨论】:

    • 谢谢,非常简洁。但是,目的是返回Option&lt;&amp;T&gt;,因此我不必自己取消该框。这里的Box 只是存储一个dyn Something。是否可以取消引用到Option&lt;&amp;T&gt;
    • @GuerlandoOCs 不幸的是,如答案中所示,Deref 特征将deref 的返回类型指定为&amp;Self::Target。我想您可以为此添加一个方法(可能称为as_ref)。但在许多情况下它不应该引起太多关注 - 在处理 Option 之后,自动取消引用和强制通常会处理最后一步。
    • 但是我为什么不能简单地说type Target = Option&lt;T&gt;?这是我没有得到的部分。我知道我们必须返回&amp;Self::Target
    • @GuerlandoOCs 我认为您将Option&lt;&amp;T&gt;&amp;Option&lt;T&gt; 混为一谈。使用type Target = Option&lt;T&gt;,你会得到&amp;Option&lt;T&gt;,它假设你已经在内存中的某个地方设置了Option&lt;T&gt;(不是T),并指向它。由于我们只有Mutex&lt;Option&lt;Box&lt;T&gt;&gt;&gt;,我们可以使用&amp;Option&lt;Box&lt;T&gt;&gt;&amp;Box&lt;T&gt;&amp;T,但不能使用&amp;Option&lt;T&gt;。我们想要的实际上是Option&lt;&amp;T&gt;,它是对T 的可空引用,而不是&amp;Option&lt;T&gt;,但Deref 的接口禁止这样做。
    • Deref trait 是否允许我设置type Target= Option&lt;&amp;T&gt;,但我无法完成这项工作,因为我必须在Option&lt;&amp;T&gt; 函数内创建对象Option&lt;&amp;T&gt;,这将迫使引用是短暂的,而不是生活在 Self 的生命周期中?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-08
    • 1970-01-01
    • 2015-03-03
    • 2022-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多