简体   繁体   English

如何为具有“租用”引用的类型实现特征

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

NB: I tried to keep this post as concise as possible, the full code can be found at https://github.com/pchampin/pair_trait .注意:我尽量保持这篇文章的简洁,完整的代码可以在https://github.com/pchampin/pair_trait找到。

The problem问题

I have defined the following trait:我定义了以下特征:

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

I have generic implementations of this trait for (T,T) and [T;2] for any T implementing Borrow<str> .对于任何实现Borrow<str> (T,T)我都有(T,T)[T;2]的这个特征的通用实现。

I also have a type, built with the rental crate, containing a String and two Cow<str> that borrow from that string:我还有一个类型,用租用的板条箱构建,包含一个String和两个从该字符串借用的Cow<str>

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

I would like this type to implement the Pair trait above, but I can't find a way to do it.我希望这种类型实现上面的Pair特征,但我找不到方法来做到这一点。

Attempt #0尝试#0

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

I know that this is not an implementation of the trait, but I just wanted to be sure that I could implement the methods first and second .我知道这不是 trait 的实现,但我只是想确保我可以实现方法firstsecond The answer is yes: the code above compiles.答案是肯定的:上面的代码可以编译。

Attempt #1尝试 #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() }
}

This fails to compile, with the message "expected lifetime parameter" for the 2nd line.这无法编译,第二行显示消息“预期寿命参数”。

This is frustrating because it is so close to attempt #0 above.这令人沮丧,因为它非常接近上面的#0 尝试。

Attempt #2尝试#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() }
}

Here the compiler is complaining about an "unconstrainted lifetime parameter" for the first line ( impl<'a> ).在这里,编译器抱怨第一行( impl<'a> )的“不受约束的生命周期参数”。

Attempt #3尝试 #3

I modified my trait Pair so that it expects a lifetime parameter.我修改了我的 trait Pair以便它需要一个生命周期参数。 Surprisingly, this works, even if the liferime parameter is never used in the definition of the trait...令人惊讶的是,即使在特征的定义中从未使用过 liferime 参数,这也是有效的......

I then wrote:然后我写道:

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() }
}

Now the compiler complains that it "cannot infer an appropriate lifetime for autoref" in both methods...现在编译器抱怨它在这两种方法中“无法推断自动引用的适当生命周期”......

Anyway, my intuition is that this is not the right path: the lifetime for which the returned Cow can not be specified independantly of that of self ...无论如何,我的直觉是这不是正确的道路:返回的Cow的生命周期不能独立于self的生命周期指定......

Attempt #4尝试 #4

Ideally, this is what I would like to write:理想情况下,这就是我想写的:

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() }
}

but obviously, the compiler doesn't know about the self lifetime.但显然,编译器不知道self生命周期。

Unfortunately, the fully intended design is currently unachievable.不幸的是,目前无法实现完全预期的设计。 Still, we can adapt attempt #3 to sort-of work.不过,我们可以将尝试 #3 调整为某种工作。

The idea of returning a &Self::Item is slightly ill-formed, because the associated type Item already represents a borrowed value.返回&Self::Item的想法有点格式错误,因为关联类型Item已经表示一个借用值。 It makes more sense to return it directly:直接返回更有意义:

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

But then you would stumble with the incapability of describing this Item as a Cow<'a, str> where 'a is the lifetime of self .但是随后您会发现无法将这个Item描述为Cow<'a, str> ,其中'aself的生命周期。 Attempt 3 was close to a solution by adding a lifetime parameter to the trait itself, thus making this arbitrary lifetime a higher-ranked argument to the trait.通过向特征本身添加生命周期参数,尝试 3 接近于解决方案,从而使这个任意生命周期成为特征的更高级别的参数。

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

This Pair<'a> now defines a pair of elements bound to 'a , and are not necessarily contained by self .这个Pair<'a>现在定义了一对绑定到'a的元素,并且不一定包含在self One possible implementation:一种可能的实现:

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)
    }
}

Full example in the Rust Playground Rust Playground 中的完整示例

This approach comes at the expense of polluting all APIs relying on this trait with higher ranked trait bounds, so that we can implement Pair<'a> for all lifetimes 'a .这种方法的代价是污染所有依赖于具有更高等级特征边界的特征的 API,因此我们可以为所有生命周期'a实现Pair<'a> For example:例如:

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

In order to achieve this 'self lifetime for constraining the associated type Item , we need Generic Associated Types (GATs).为了实现用于约束关联类型Item 'self生命周期”,我们需要通用关联类型(GAT)。 Once implemented, we'll be able to write something like this:实现后,我们将能够编写如下内容:

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.

相关问题 如何为结构体的引用实现 Add trait? - How do I implement the Add trait for a reference to a struct? 如何制作一个仅限于实现另一个特征的类型的特征,其中 `&amp;Self` 自我是特征的类型? - How do I make a trait that is restricted to types who implement another trait where `&Self` self is a trait's type? 如何使用泛型方法实现特征? - How do I implement a trait with a generic method? 如何在柯里化函数上实现特征? - How do I implement a trait on a curried function? 如何指定一个带引用的闭包,并返回实现与引用具有相同生命周期的特征的任何类型? - How do I specify a closure that takes a reference and returns any type implementing a trait with the same lifetime as the reference? 如何为我不拥有的类型实现我不拥有的特征? - How do I implement a trait I don't own for a type I don't own? 如果在函数内创建引用,如何将泛型类型与需要使用生命周期参数的特征绑定在一起? - How do I bound a generic type with a trait that requires a lifetime parameter if I create the reference inside the function? 如何实现泛型类型的特征? - How to implement a trait for generic type? 如何在包含锈特质的泛型类型上实现deref? - How do you implement deref on a generic type containing a trait in rust? 如何返回对添加到特征对象向量的具体类型的引用? - How do I return a reference to a concrete type that was added to a vector of trait objects?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM