簡體   English   中英

如果你這樣做該死,如果你不這樣做該死: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 有更多字段,但為了簡單起見,我刪除了它們。 您可以在此處查看代碼片段。 代碼拋出錯誤

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>;
   |                ^^^^

不管你說什么,我都會提前 go 並將該參數添加到目標。 但是現在我又遇到了另一個錯誤:

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 的東西?

這里有幾個問題。 首先:

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其他相關字段,僅此而已!

由於DerefMut繼承自Deref ,因此您不必指定Targetpub trait DerefMut: Deref {Deref實現中使用Target定義。

Deref trait 非常特殊,“普通”用戶不能真正使用它,幾乎只有 std 可以為新類型實現它。

這是因為它借用了自我並返回了“其他”問題的引用,這不是暫時的,std 使用它來控制 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以返回Target之類的類型slice

另一個例子是PathBuf

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

這里更清楚Path::new創建一個胖指針。 因此, Target 不能是其他不能自包含或已存在於您Self中的東西。

正如文檔所說:

因此,應該只為智能指針實現 Deref 以避免混淆。

我認為您真正想要的是實施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
    }
}

你愛怎么做就怎么做。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM