该死的,如果你这样做,如果你不这样做,该死的:无论是否有生命周期参数,Rust 编译器都会抱怨

Damned if you do, damned if you don't: Rust compiler complains regardless whether there's a lifetime parameter or not

我正在尝试决定是否应该向我的 impls 添加生命周期参数,但似乎我处于“如果你这样做该死,如果你不这样做该死”的情况,因为无论是否有编译器都会抱怨是否为生命周期参数。

pub struct TurtleRef<'a> {
    t: &'a BorrowedTurtle<'a>,
}

impl TurtleRef<'_> {
    pub fn borrowed_turtle(&self) -> BorrowedTurtle {
        *self.t
    }

    pub fn new(r: Turtle) -> TurtleRef {
        TurtleRef{t: &BorrowedTurtle{ t:r}}
    }
}

pub struct BorrowedTurtle<'a> {
    t: Turtle<'a>,
}

impl<'a> std::ops::Deref for BorrowedTurtle<'_> {
    type Target = Turtle<'a>;

    fn deref(&self) -> &Self::Target {
        &self.t
    }
}

impl<'a> std::ops::DerefMut for BorrowedTurtle<'_> {
    type Target = Turtle<'a>;
    fn deref_mut(&mut self) -> &mut Self::Target {
        &self.t
    }
}

pub struct Turtle<'a> {
    children: Vec<Turtle<'a>>,
}

Turtle 有更多字段,但为了简单起见,我删除了它们。您可以看到代码片段 here。代码抛出错误

error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
  --> src/campus.rs:54:6
   |
54 | impl<'a> std::ops::Deref for BorrowedTurtle<'_> {
   |      ^^ unconstrained lifetime parameter

没问题,我会删除该参数,因为它引起了这么大的麻烦。但是在删除它之后,我得到了一大堆新错误:


error[E0261]: use of undeclared lifetime name `'a`
  --> src/campus.rs:55:26
   |
55 |     type Target = Turtle<'a>;
   |                          ^^ undeclared lifetime
   |
help: consider introducing lifetime `'a` here
   |
54 | impl<'a> std::ops::Deref for BorrowedTurtle<'_> {
   |     ^^^^
help: consider introducing lifetime `'a` here
   |
55 |     type Target<'a> = Turtle<'a>;
   |                ^^^^

不管你说什么,我都会继续并将该参数添加到目标。但是现在我又遇到了另一个错误:

error[E0658]: generic associated types are unstable
  --> src/campus.rs:55:5
   |
55 |     type Target<'a> = Turtle<'a>;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information

所以无论我做什么,似乎我运行都陷入了重大错误。如何在不从头开始的情况下停止这些错误?我想保留 impls、structs 和 deref 函数,所以我唯一应该改变的是它们的实现。

另外,我收到错误

error[E0437]: type `Target` is not a member of trait `std::ops::DerefMut`
  --> src/campus.rs:64:5
   |
64 |     type Target = Turtle<'a>;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `std::ops::DerefMut`

因为 Turtle 没有实现 DerefMut,事实上 Turtle 不应该实现 DerefMut。是否对 Turtle 进行了轻微修改,从而导致某些东西已经实现了 DerefMut?

由于 DerefMut 继承自 Deref,您不必指定 Targetpub trait DerefMut: Deref { 使用 Target 在 [=14= 中定义] 实施。

Deref trait 非常特殊,它不能被“普通”用户真正使用,几乎只有 std 可以为新类型实现它。

这是因为它是借用自己和 return 引用“其他东西”问题是这个其他东西不能是临时的,例如标准使用它控制 rust 生态系统能够做到这一点Vec 实施:

impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
    fn deref_mut(&mut self) -> &mut [T] {
        unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
    }
}

如您所见,slice 是一个“胖指针”,因此它只需要一个引用即可生效,您几乎可以只实现 Deref 到 return Target 对于像 slice.

这样的类型

另一个例子是 PathBuf:

impl ops::Deref for PathBuf {
    type Target = Path;
    #[inline]
    fn deref(&self) -> &Path {
        Path::new(&self.inner)
    }
}

这里就更清楚了Path::new 创建一个胖指针。因此,Target 不能是不能自包含或已经存在于您的 Self.

中的其他东西

正如 documentation 所说:

Because of this, Deref should only be implemented for smart pointers to avoid confusion.

我认为您真正想要的是实现 Borrow。综上所述......这里是一个工作代码:

impl<'a> std::ops::Deref for BorrowedTurtle<'a> {
    type Target = Turtle<'a>;

    fn deref(&self) -> &Self::Target {
        &self.t
    }
}

impl std::ops::DerefMut for BorrowedTurtle<'_> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.t
    }
}

随心所欲

这里有几个问题。第一:

error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
  --> src/campus.rs:54:6
   |
54 | impl<'a> std::ops::Deref for BorrowedTurtle<'_> {
   |      ^^ unconstrained lifetime parameter

您要么使用匿名生命周期,要么不使用。在这里,你声明了'a,所以使用它:

impl<'a> std::ops::Deref for BorrowedTurtle<'a> {

要使用省略的生命周期,您不必声明它:

impl std::ops::Deref for BorrowedTurtle<'_> {

但是这里要引用Target中的生命周期,不能省略。

第二个:

error[E0437]: type `Target` is not a member of trait `std::ops::DerefMut`
  --> src/lib.rs:28:5
   |
28 |     type Target = Turtle<'a>;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `std::ops::DerefMut`

DerefMut 没有 Target 成员,因为它重用了其超特性 Deref 中的成员。这是为了确保项目必须 DerefDerefMut 相同 Target:

impl<'a> std::ops::Deref for BorrowedTurtle<'a> {
    type Target = Turtle<'a>;

    fn deref(&self) -> &Self::Target {
        &self.t
    }
}

impl std::ops::DerefMut for BorrowedTurtle<'_> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.t
    }
}

最后,您现在会收到未使用 'a 的错误消息:

error[E0392]: parameter `'a` is never used
  --> src/lib.rs:15:27
   |
15 | pub struct BorrowedTurtle<'a> {
   |                           ^^ unused parameter
   |
   = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`

这是因为您有几个递归类型实际上并未使用生命周期:

// 'a isn't actually used for anything

pub struct Turtle<'a> {
    children: Vec<Turtle<'a>>,
}

pub struct BorrowedTurtle<'a> {
    t: Turtle<'a>,
}

我假设您为了这个答案省略了其他使用 'a 的相关字段,仅此而已!