[英]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
特征,但我找不到方法來做到這一點。
impl SelfSustainedPair {
pub fn first(&self) -> &Cow<str> { self.suffix().first() }
pub fn second(&self) -> &Cow<str> { self.suffix().second() }
}
我知道這不是 trait 的實現,但我只是想確保我可以實現方法first
和second
。 答案是肯定的:上面的代碼可以編譯。
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 嘗試。
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>
)的“不受約束的生命周期參數”。
我修改了我的 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
的生命周期指定......
理想情況下,這就是我想寫的:
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>
,其中'a
是self
的生命周期。 通過向特征本身添加生命周期參數,嘗試 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)
}
}
這種方法的代價是污染所有依賴於具有更高等級特征邊界的特征的 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.