簡體   English   中英

具有特征的類型定義:指定顯式生命周期界限的差異?

[英]Type definition with a trait: Differences of specifying an explicit lifetime bound?

當我在類型定義中使用特征時,我在理解生命周期綁定要求時遇到問題。 例如:

trait Kind { /* ... */ }
type CollectionOfKind<'a> = Vec<&'a Kind>;
// => error: explicit lifetime bound required

已經針對結構中的特征(答案 1答案 2 )討論了對生命周期邊界的要求。 起初,我在這里完全無法應用“添加生命周期”的方法,因為這不起作用:

type CollectionOfKind<'a> = Vec<&'a Kind + 'a>;
type CollectionOfKind<'a> = Vec<&'a Kind + 'static>;

但是,由於@Shepmaster 指出的加號優先,這只是一個語法問題。

總的來說,我現在找到了三種指定生命周期界限的方法:

// Version 1: Adding 'static to the trait itself
trait Kind : 'static { /* ... */ }
type CollectionOfKind<'a> = Vec<&'a Kind>;
// Version 2: Adding 'static to the type definition
trait Kind { /* ... */ }
type CollectionOfKind<'a> = Vec<&'a (Kind + 'static)>;
// Version 3: Adding the lifetime of the reference to the trait object (?)
trait Kind { /* ... */ }
type CollectionOfKind<'a> = Vec<&'a (Kind + 'a)>;

我不明白的是:這三種情況之間的確切區別是什么?

我的問題:

為了看到差異,我試圖理解其他答案中提到的某些要點。 例如,在上面鏈接的答案 2 中,我發現了以下我不完全理解的提示:

在這種情況下, 'static要求底層對象必須是一個真正的結構體,或者一個&'static引用,但不允許其他引用。

底層對象必須是“真實”結構體是什么意思? 一個結構如何實現特性而不是“真實的”?

同樣對於@Shepmaster 引用的引用:

你必須指定兩次生命周期:一次是引用的生命周期,一次是 trait 對象本身,因為 trait 可以為引用實現,如果底層對象是引用,你也必須指定它的生命周期。

老實說,我不明白為什么必須指定兩次。 我雖然 trait 對象是通過對實現某個 trait 的對象的引用來定義的。 所以它根據定義(?)是一個引用,因此,無論如何都有生命周期?

回答新問題

你真的有兩個正交的情況 我將首先解決更簡單的問題,即 #2 和 #3 的區別。 評論符合我希望是一個代表性的例子:

trait Kind { 
    fn trait_fn(&self) -> u8 { 0 }
}

type CollectionOfKind1<'a> = Vec<&'a (dyn Kind + 'static)>;
type CollectionOfKind2<'a> = Vec<&'a (dyn Kind + 'a)>;

struct Alpha;
impl Kind for Alpha {}

struct Beta<'b> {
    name: &'b str,
}
impl<'a> Kind for Beta<'a> {}

fn main() {
    let name = "world".to_string();

    // Doesn't need/have it's own lifetime.
    let a = Alpha;
    // Has a reference to something with the 'static lifetime.
    let b1 = Beta { name: "hello" };
    // Has a reference to something with the lifetime of `name`,
    // which is less than 'static.
    let b2 = Beta { name: &name[..] };  

    // Our vector is composed of references to
    // things that *might* have a reference themselves!
    let mut c1: CollectionOfKind1 = Vec::new();
    c1.push(&a);
    c1.push(&b1);
    // c1.push(&b2); // error: `name` does not live long enough
    
    let mut c2: CollectionOfKind2 = Vec::new();
    c2.push(&a);
    c2.push(&b1);
    c2.push(&b2); // Hooray
}

這里需要注意的是,生命周期不必相同 你可以寫:

type CollectionOfKind2<'a, 'b> = Vec<&'a (dyn Kind + 'b)>;

第二件事是trait Foo : 'static的含義trait Foo : 'static 我在這里不太確定,但我寫了這個小例子:

trait Foo : 'static {}

fn x(a: &Foo) {}

fn main() {
    x(&3u8);
}

編譯過程中出現此錯誤

必須實現特征Foo才能轉換為對象類型Foo + 'static

基於此,我認為Foo : 'static只是Foo + 'static另一種寫法。 我能想到的主要區別是,它限制將永遠不能與非一個結構實現的特質'static壽命:

struct B<'a> {
    b: &'a str,
}

impl<'a> Foo for B<'a> {}

有錯誤

聲明的生命周期邊界不滿足 [...] 但生命周期參數必須比靜態生命周期長

原答案

我看到你已經發現了這一點,但你可能想要更新你的 Rust 版本。 如果我在 Playpen 上編譯您的代碼,我會收到有關如何修復它的建議:

error: expected a path on the left-hand side of `+`, not `&'a Kind` [E0178]
type CollectionOfKind<'a> = Vec<&'a Kind + 'a>;
                                ^~~~~~~~
note: perhaps you meant `&'a (Kind + 'a)`? (per RFC 438)
type CollectionOfKind<'a> = Vec<&'a Kind + 'a>;
                                ^~~~~~~~

這引用了RFC 438, Precedence of Plus

暫無
暫無

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

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