简体   繁体   English

实现一个特征方法,返回一个拥有类型的有界生命周期引用

[英]Implementing a trait method returning a bounded lifetime reference for owned type

Let's assume I have this struct and this trait:假设我有这个结构和这个特征:

#[derive(Debug)]
pub struct New<T>(T);

pub trait AsRefNew<'a> {
    fn as_ref(&self) -> New<&'a str>;
}

That is, the AsRefNew trait allows to return a reference with a given lifetime 'a wrapped in a New newtype.也就是说, AsRefNew特性允许返回具有给定生命周期的引用'a包装在New类型中。 This lifetime 'a may be different (and will be) from the lifetime of the &self parameter.此生命周期'a可能与&self参数的生命周期不同(并且将不同)。

Now I can implement this trait for a New(&str) , and make it so that the lifetime of the output is the lifetime of the wrapped &str :现在我可以为New(&str)实现这个特性,并使 output 的生命周期就是包装的&str的生命周期:

impl<'a> AsRefNew<'a> for New<&'a str> {
    fn as_ref(&self) -> New<&'a str>{
        New(self.0)
    }
}

My problem is that I would like to implement the trait for New(String) , and this time, I would like 'a to actually match the lifetime of self .我的问题是我想为New(String)实现特性,而这一次,我希望'a真正匹配self的生命周期。 My understanding is that something like that should work:我的理解是这样的事情应该有效:

impl<'a> AsRefNew<'a> for New<String> where Self: 'a{
    fn as_ref(&self) -> New<&'a str> {
        New(self.0.as_str())
    }
}

Except it does not:除了它不:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/main.rs:16:20
   |
16 |         New(self.0.as_str())
   |                    ^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 15:5...
  --> src/main.rs:15:5
   |
15 |     fn as_ref(&self) -> New<&'a str> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:16:13
   |
16 |         New(self.0.as_str())
   |             ^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 14:6...
  --> src/main.rs:14:6
   |
14 | impl<'a> AsRefNew<'a> for New<String> where Self: 'a{
   |      ^^
note: ...so that the expression is assignable
  --> src/main.rs:16:9
   |
16 |         New(self.0.as_str())
   |         ^^^^^^^^^^^^^^^^^^^^
   = note: expected `New<&'a str>`
              found `New<&str>`

I tried different variations of lifetimes and generic, but I can not find a better way to express the fact that I, in this case, want 'a to match '_ .我尝试了生命周期和通用的不同变体,但我找不到更好的方式来表达我在这种情况下希望'a匹配'_的事实。

The goal is to have this snippet to work:目标是让这个片段起作用:

fn main() {
    // This works:
    let a = String::from("Hey");
    let b;
    {
        let c = New(a.as_str());
        b = c.as_ref().0;
    }
    println!("{:?}", b);
    
    // I would like that to work as well:
    let a = String::from("Ho");
    let b;
    let c = New(a);
    {
        b = c.as_ref().0;
    }
    println!("{:?}", b);
}

Any ideas?有任何想法吗?

As explained by Sven, in order to make that work, we would need two different method prototypes, and that is not possible with the AsRefNew trait as it is defined.正如 Sven 所解释的那样,为了实现这一点,我们需要两个不同的方法原型,而这对于定义的AsRefNew特性是不可能的。

Still, it can be modified to make the small snippet work by, eg introducing a second lifetime in the signature:尽管如此,它仍然可以通过在签名中引入第二个生命周期来修改以使小片段工作:

#[derive(Debug)]
pub struct New<T>(T);

pub trait AsRefNew<'b, 'a> {
    fn as_ref(&'b self) -> New<&'a str>;
}

impl<'a> AsRefNew<'_, 'a> for New<&'a str> {
    fn as_ref(&self) -> New<&'a str>{
        New(self.0)
    }
}

impl<'b, 'a> AsRefNew<'b, 'a> for New<String> where 'b:'a {
    fn as_ref(&'b self) -> New<&'a str> {
        New(self.0.as_str())
    }
}

impl<T> New<T> {
    pub fn test<'b, 'a>(&'b self) -> New<&'a str> where Self: AsRefNew<'b, 'a> {
        self.as_ref()
    }
}

The following snippet now works:以下代码段现在有效:

fn main() {
    // This works:
    let a = String::from("Hey");
    let b;
    {
        let c = New(a.as_str());
        b = c.as_ref().0;
    }
    println!("{:?}", b);
    
    // It now works
    let a = String::from("Ho");
    let b;
    let c = New(a);
    {
        b = c.as_ref().0;
    }
    println!("{:?}", b);
}

And so is this generic implementation of a method on the New type: New类型上方法的通用实现也是如此:

impl<T> New<T> {
    pub fn test<'b, 'a>(&'b self) -> New<&'a str> where Self: AsRefNew<'b, 'a> {
        self.as_ref()
    }
}

The only problem now is that the signature is super ugly.现在唯一的问题是签名超级难看。 I wonder whether this could made simpler with gats.我想知道这是否可以通过 gats 变得更简单。

This isn't really possible.这真的不可能。 Trait methods can only have a single prototype, and all implementations have to match that prototype.特征方法只能有一个原型,所有实现都必须匹配该原型。

For the case New<&'a str> , your prototype needs to be what you have对于案例New<&'a str> ,您的原型需要是您拥有的

fn as_ref(&self) -> New<&'a str>;

For the case New<String> , on the other hand, you would need另一方面,对于New<String>的情况,您需要

fn as_ref<'b>(&'b self) -> New<&'b str>;

instead, ie the lifetime of the return value needs to be tied to the lifetime of the self reference.相反,即返回值的生命周期需要与self引用的生命周期相关联。 This prototype is different, since lifetimes are part of the prototype.这个原型是不同的,因为生命周期是原型的一部分。

Your attempt to solve this with a trait bound Self: 'a can't work.你试图用一个特征绑定Self: 'a来解决这个问题是行不通的。 The type Self is New<String> here, which does not contain any references, so it in fact trivially fulfils Self: 'static , and thus any lifetime bound.这里的Self类型是New<String> ,它不包含任何引用,所以它实际上很简单地实现了Self: 'static ,因此实现了任何生命周期限制。 The bound does not further constrain the Self type in any way.绑定不会以任何方式进一步约束Self类型。 You can't restrict the lifetime of the self reference at the impl level, and bounding it at the function definition level will result in diverging from the prototype in the trait definition, as explained above.您不能在 impl 级别限制self引用的生命周期,并且将其限制在 function 定义级别将导致偏离特征定义中的原型,如上所述。

For the same reason, you can't get an &'a str from a Cow<'a, str> by dereferencing.出于同样的原因,您无法通过解除引用从Cow<'a, str>中获取&'a str The Cow might be owned, in which case the returned reference can only live as long a the self reference used for dereferencing. Cow可能被拥有,在这种情况下,返回的引用只能与用于取消引用的self引用一样长。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为具有生命周期的类型实现 Borrow trait - Implementing Borrow trait for a type with a lifetime 如果生命周期未被使用,为什么在引用类型上实现特征时需要生命周期,在Rust <1.31? - Why is a lifetime needed when implementing a trait on a reference type if the lifetime is otherwise unused, in Rust < 1.31? 为类型引用实现特征时返回对临时值的引用时出错 - Error returning reference to a temporary value when implementing a trait for a type reference 如何指定一个带引用的闭包,并返回实现与引用具有相同生命周期的特征的任何类型? - How do I specify a closure that takes a reference and returns any type implementing a trait with the same lifetime as the reference? Traits,通过返回 `Self::Item` 的 trait 方法返回对拥有字段的引用 - Traits, returning a reference to an owned field via a trait method that returns `Self::Item` 用返回通用特征的方法实现特征 - Implementing trait with method returning generic trait 从 trait 方法返回对结构字段的可变引用时,如何修复生命周期不匹配? - How do I fix the lifetime mismatch when returning a mutable reference to the struct's field from a trait method? 用生命周期实现索引特征 - Implementing Index trait with lifetime 为实现具有关联生命周期的特征的泛型类型实现特征时的生命周期问题 - Lifetime issue while implementing a trait for a generic type which implements a trait with an associated lifetime 无法推断闭包的寿命,该闭包返回包含引用的盒装特征 - Cannot infer a lifetime for a closure returning a boxed trait that contains a reference
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM