繁体   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