簡體   English   中英

如何為具有“租用”引用的類型實現特征

[英]How do I implement a trait for a type with "rented" reference

注意:我盡量保持這篇文章的簡潔,完整的代碼可以在https://github.com/pchampin/pair_trait找到。

問題

我定義了以下特征:

pub trait Pair {
    type Item: Borrow<str>;
    fn first(&self) -> &Self::Item;
    fn second(&self) -> &Self::Item;
}

對於任何實現Borrow<str> (T,T)我都有(T,T)[T;2]的這個特征的通用實現。

我還有一個類型,用租用的板條箱構建,包含一個String和兩個從該字符串借用的Cow<str>

#[rental(covariant)]
pub struct SelfSustainedPair {
    line: String,
    pair: (Cow<'line, str>, Cow<'line, str>),
}

我希望這種類型實現上面的Pair特征,但我找不到方法來做到這一點。

嘗試#0

impl SelfSustainedPair {
    pub fn first(&self) -> &Cow<str> { self.suffix().first() }
    pub fn second(&self) -> &Cow<str> { self.suffix().second() }
}

我知道這不是 trait 的實現,但我只是想確保我可以實現方法firstsecond 答案是肯定的:上面的代碼可以編譯。

嘗試 #1

impl Pair for SelfSustainedPair {
    type Item = Cow<str>;
    fn first(&self) -> &Cow<str> { self.suffix().first() }
    fn second(&self) -> &Cow<str> { self.suffix().second() }
}

這無法編譯,第二行顯示消息“預期壽命參數”。

這令人沮喪,因為它非常接近上面的#0 嘗試。

嘗試#2

impl<'a> Pair for SelfSustainedPair {
    type Item = Cow<'a, str>;
    fn first(&self) -> &Cow<'a, str> { self.suffix().first() }
    fn second(&self) -> &Cow<'a, str> { self.suffix().second() }
}

在這里,編譯器抱怨第一行( impl<'a> )的“不受約束的生命周期參數”。

嘗試 #3

我修改了我的 trait Pair以便它需要一個生命周期參數。 令人驚訝的是,即使在特征的定義中從未使用過 liferime 參數,這也是有效的......

然后我寫道:

impl<'a> Pair<'a> for SelfSustainedPair {
    type Item = Cow<'a, str>;
    fn first(&self) -> &Cow<'a, str> { self.suffix().first() }
    fn second(&self) -> &Cow<'a, str> { self.suffix().second() }
}

現在編譯器抱怨它在這兩種方法中“無法推斷自動引用的適當生命周期”......

無論如何,我的直覺是這不是正確的道路:返回的Cow的生命周期不能獨立於self的生命周期指定......

嘗試 #4

理想情況下,這就是我想寫的:

impl Pair for SelfSustainedPair {
    type Item = Cow<'self, str>;
    fn first(&self) -> &Cow<str> { self.suffix().first() }
    fn second(&self) -> &Cow<str> { self.suffix().second() }
}

但顯然,編譯器不知道self生命周期。

不幸的是,目前無法實現完全預期的設計。 不過,我們可以將嘗試 #3 調整為某種工作。

返回&Self::Item的想法有點格式錯誤,因為關聯類型Item已經表示一個借用值。 直接返回更有意義:

pub trait Pair {
    type Item: Borrow<str>;
    fn first(&self) -> Self::Item;
    fn second(&self) -> Self::Item;
}

但是隨后您會發現無法將這個Item描述為Cow<'a, str> ,其中'aself的生命周期。 通過向特征本身添加生命周期參數,嘗試 3 接近於解決方案,從而使這個任意生命周期成為特征的更高級別的參數。

pub trait Pair<'a> {
    type Item: 'a + Borrow<str>;
    fn first(&'a self) -> Self::Item;
    fn second(&'a self) -> Self::Item;
}

這個Pair<'a>現在定義了一對綁定到'a的元素,並且不一定包含在self 一種可能的實現:

impl<'a> Pair<'a> for (String, String) {
    type Item = Cow<'a, str>;

    fn first(&'a self) -> Self::Item {
        Cow::Borrowed(&self.0)
    }
    fn second(&'a self) -> Self::Item {
        Cow::Borrowed(&self.1)
    }
}

Rust Playground 中的完整示例

這種方法的代價是污染所有依賴於具有更高等級特征邊界的特征的 API,因此我們可以為所有生命周期'a實現Pair<'a> 例如:

fn foo<T>(pair: T)
where
    for<'a> T: Pair<'a>,
{
    unimplemented!()
}

為了實現用於約束關聯類型Item 'self生命周期”,我們需要通用關聯類型(GAT)。 實現后,我們將能夠編寫如下內容:

pub trait Pair {
    type Item<'a>: Borrow<str>;
    fn first(&'a self) -> Self::Item<'a>;
    fn second(&'a self) -> Self::Item<'a>;
}

impl Pair for (String, String) {
    type Item<'a> = Cow<'a, str>;

    fn first(&'a self) -> Self::Item<'a> {
        Cow::Borrowed(&self.0)
    }
    fn second(&'a self) -> Self::Item<'a> {
        Cow::Borrowed(&self.1)
    }
}

暫無
暫無

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

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