[英]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.