cannot infer an appropriate lifetime for borrow expression due to conflicting requirements - reference

pub struct FooStruct<'a> {
pub bars: Vec<&'a str>,
}
pub trait FooTrait<'a> {
fn getBars(&self) -> &'a Vec<&'a str>;
}
impl<'a> FooTrait<'a> for FooStruct<'a> {
fn getBars(&self) -> &'a Vec<&'a str> {
&self.bars // cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
}
}
Run it: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=3211c32dd5b9244ff91777f1820ffed5
I do not understand where the requirement conflict comes from. Afaik there is no conflict since everything lives as long as the FooStruct lives.

Let's take it apart:
pub struct FooStruct<'a> {
pub bars: Vec<&'a str>,
}
FooStruct holds a container containing string slices with lifetime 'a. The container's lifetime corresponds to the lifetime of FooStruct.
pub trait FooTrait<'a> {
fn getBars(&self) -> &'a Vec<&'a str>;
}
FooTrait wants getBars to return a reference to a container holding string slices with lifetime 'a. The lifetime of the returned reference should be 'a, too.
impl<'a> FooTrait<'a> for FooStruct<'a> {
fn getBars(&self) -> &'a Vec<&'a str> {
&self.bars
}
}
Here, getBars returns a reference to self.bars which is a container of string slices with lifetime 'a. So far, so good.
However, what is the lifetime of &self.bars? It corresponds to the lifetime of self (i.e. the respective FooStruct).
What is the lifetime of self? It is 'self (an implicit lifetime).
However, the FooTrait requires that the returned reference lifetime is 'a, so that does not match FooTrait's declaration.
One solution is to separate the lifetimes in FooTrait:
pub trait FooTrait<'a> {
fn getBars<'s>(&'s self) -> &'s Vec<&'a str>;
}
impl<'a> FooTrait<'a> for FooStruct<'a> {
fn getBars<'s>(&'s self) -> &'s Vec<&'a str> {
&self.bars
}
}

Related

Trait for conversion of references and owned values to Cow

I have a function that can handle both owned and borrowed values of some type Foo by accepting a Cow<'_, Foo>. However, I'd like to make it more convenient by allowing to pass in owned or borrowed Foos directly.
Is it possible to have a conversion trait to Cow that's implemented both on a reference type and its owned version?
This is what I tried:
trait Convert<'a> : Clone {
fn into_cow(self) -> Cow<'a, Self>;
}
// Works
impl<'a> Convert<'a> for Foo {
fn into_cow(self) -> Cow<'a, Self> {
println!("owned");
Cow::Owned(self)
}
}
// Doesn't work
impl<'a> Convert<'a> for &'a Foo {
fn into_cow(self) -> Cow<'a, Self> {
println!("borrowed");
Cow::Borrowed(self)
}
}
The borrowed version says that Borrowed expected a &&'a Foo but found a &'a Foo.
Self in the implementation of a trait for &Foo is &Foo, so into_cow() doesn't return the same type in both impls.
One solution would be to change the return type to Cow<'a, Foo>, but that of course limits the trait to only work on Foo.
A better way is to make the owned type a generic parameter of Convert like this:
trait Convert<'a, T: Clone> {
fn into_cow(self) -> Cow<'a, T>;
}
impl<'a, T: Clone> Convert<'a, T> for T {
fn into_cow(self) -> Cow<'a, T> {
println!("owned");
Cow::Owned(self)
}
}
impl<'a, T: Clone> Convert<'a, T> for &'a T {
fn into_cow(self) -> Cow<'a, T> {
println!("borrowed");
Cow::Borrowed(self)
}
}
fn take_foo<'a>(foo: impl Convert<'a, Foo>) {
let cow = foo.into_cow();
}
fn main() {
take_foo(&Foo{});
take_foo(Foo{});
}
Do you ever make use of the ownership, or always reborrow it? If only reborrowing, is std::convert::AsRef what you're looking for?
fn take_foo(foo: impl AsRef<Foo>) {
let foo: &Foo = foo.as_ref();
todo!();
}

Lifetimes for traits

Let there is some struct:
struct ResourceData { }
We can create its list:
pub struct ResourceList
{
pub v: Vec<ResourceData>,
}
but if I add a level of indirection:
pub trait Resource<'a> {
fn data(&self) -> &'a ResourceData;
fn data_mut(&mut self) -> &'a mut ResourceData;
}
then I am messed:
pub struct ResourceList2<R: Resource<'a>> // What should be 'a?
{
pub v: Vec<R>,
}
What should be 'a?
'a could be the lifetime of the vector, but if an element is removed, the lifetime of the references shorten, because references break. So, accordingly my understanding, 'a isn't the lifetime of the vector.
Resource should not have a lifetime argument, but instead just use elided lifetimes:
pub trait Resource {
fn position(&self) -> &ResourceData;
fn position_mut(&mut self) -> &mut ResourceData;
}
After understanding this, the question disappears, just:
pub struct ResourceList2<R: Resource> // What should be 'a?
{
pub v: Vec<R>,
}

Generic parameter with reference used as function pointer argument

I am having trouble figuring out what lifetime parameter will work for this, so my current workarounds include transmutes or raw pointers. I have a structure holding a function pointer with a generic as a parameter:
struct CB<Data> {
cb: fn(Data) -> usize
}
I would like to store an instance of that, parameterized by some type containing a reference, in some other structure that implements a trait with one method, and use that trait method to call the function pointer in CB.
struct Holder<'a> {
c: CB<Option<&'a usize>>
}
trait Exec {
fn exec(&self, v: &usize) -> usize;
}
impl<'a> Holder<'a> {
fn exec_aux(&self, v: &'a usize) -> usize {
(self.c.cb)(Some(v))
}
}
impl<'a> Exec for Holder<'a> {
fn exec(&self, v: &usize) -> usize
{
self.exec_aux(v)
}
}
This gives me a lifetime error for the 'Exec' impl of Holder:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
Simply calling exec_aux works fine as long as I don't define that Exec impl:
fn main() {
let h = Holder { c: CB{cb:cbf}};
let v = 12;
println!("{}", h.exec_aux(&v));
}
Also, making CB not generic also makes this work:
struct CB {
cb: fn(Option<&usize>) -> usize
}
The parameter in my actual code is not a usize but something big that I would rather not copy.
The lifetimes in your Exec trait are implicitly this:
trait Exec {
fn exec<'s, 'a>(&'s self, v: &'a usize) -> usize;
}
In other words, types that implement Exec need to accept any lifetimes 's and 'a. However, your Holder::exec_aux method expects a specific lifetime 'a that's tied to the lifetime parameter of the Holder type.
To make this work, you need to add 'a as a lifetime parameter to the Exec trait instead, so that you can implement the trait specifically for that lifetime:
trait Exec<'a> {
// ^^^^ vv
fn exec(&self, v: &'a usize) -> usize;
}
impl<'a> Exec<'a> for Holder<'a> {
// ^^^^ vv
fn exec(&self, v: &'a usize) -> usize
{
self.exec_aux(v)
}
}
The problem here is that the Exec trait is too generic to be used in this way by Holder. First, consider the definition:
trait Exec {
fn exec(&self, v: &usize) -> usize;
}
This definition will cause the compiler to automatically assign two anonymous lifetimes for &self and &v in exec. It's basically the same as
fn exec<'a, 'b>(&'a self, v: &'b usize) -> usize;
Note that there is no restriction on who needs to outlive whom, the references just need to be alive for the duration of the method call.
Now consider the definition
impl<'a> Holder<'a> {
fn exec_aux(&self, v: &'a usize) -> usize {
// ... doesn't matter
}
}
Since we know that &self is a &Holder<'a> (this is what the impl refers to), we need to have at least a &'a Holder<'a> here, because &'_ self can't have a lifetime shorter than 'a in Holder<'a>. So this is saying that the two parameters have the same lifetime: &'a self, &'a usize.
Where it all goes wrong is when you try to combine the two. The trait forces you into the following signature, which (again) has two distinct implicit lifetimes. But the actual Holder which you then try to call a method on forces you to have the same lifetimes for &self and &v.
fn exec(&self, v: &usize) -> usize {
// Holder<'a> needs `v` to be `'a` when calling exec_aux
// But the trait doesn't say so.
self.exec_aux(v)
}
One solution is to redefine the trait as
trait Exec<'a> {
fn exec(&'a self, v: &'a usize) -> usize;
}
and then implement it as
impl<'a> Exec<'a> for Holder<'a> {
fn exec(&'a self, v: &'a usize) -> usize {
self.exec_aux(v)
}
}

Rust lifetime error

Can anyone tell what the lifetime error is in the following code? (simplified from my actual code) I've looked it over myself, but I can't figure out what is wrong or how to fix it. The problem comes when I try to add the Cell, but I'm not sure why.
use std::cell::Cell;
struct Bar<'a> {
bar: &'a str,
}
impl<'a> Bar<'a> {
fn new(foo: &'a Foo<'a>) -> Bar<'a> { Bar{bar: foo.raw} }
}
pub struct Foo<'a> {
raw: &'a str,
cell: Cell<&'a str>,
}
impl<'a> Foo<'a> {
fn get_bar(&self) -> Bar { Bar::new(&self) }
}
The compiler error is
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/foo.rs:15:32
|
15 | fn get_bar(&self) -> Bar { Bar::new(&self) }
| ^^^^^^^^
First, the solution:
use std::cell::Cell;
struct Bar<'a> {
bar: &'a str,
}
impl<'a> Bar<'a> {
fn new(foo: &Foo<'a>) -> Bar<'a> { Bar{bar: foo.raw} }
}
pub struct Foo<'a> {
raw: &'a str,
cell: Cell<&'a str>,
}
impl<'a> Foo<'a> {
fn get_bar(&self) -> Bar<'a> { Bar::new(&self) }
}
There are two problems in your code. The first is with get_bar, where you didn't specify the lifetime for the return type. When you don't specify lifetimes in signatures, Rust doesn't infer the correct lifetimes, it just blindly fills them in based on simple rules. In this specific case, what you get is effectively fn get_bar<'b>(&'b self) -> Bar<'b> which is obviously wrong, given the lifetime of self.raw (which was what you actually wanted) is 'a. See the Rust Book chapter on Lifetime Elision.
The second problem is that you're over-constraining the argument to Bar::new. &'a Foo<'a> means you require a borrow to a Foo for as long as the strings it's borrowing exist. But borrows within a type have to outlive values of said type, so the only lifetime valid in this case is where 'a matches the entire lifetime of the thing being borrowed... and that conflicts with the signature of get_bar (where you're saying &self won't necessarily live as long as 'a since it has its own lifetime). Long story short: remove the unnecessary 'a from the Foo borrow, leaving just &Foo<'a>.
To rephrase the above: the problem with get_bar was that you hadn't written enough constraints, the problem with Bar::new was that you'd written too many.
DK explained which constraints were missing and why, but I figured I should explain why the code was working before I added Cell. It turns out to be due to variance inference.
If you add in the inferred lifetimes to the original code and rename the lifetime variables to be unique, you get
struct Bar<'b> {
bar: &'b str,
}
impl<'b> Bar<'b> {
fn new(foo: &'b Foo<'b>) -> Bar<'b> { Bar{bar: foo.raw} }
}
pub struct Foo<'a> {
raw: &'a str,
cell: Cell<&'a str>,
}
impl<'a> Foo<'a> {
fn get_bar<'c>(&'c self) -> Bar<'c> { Bar::new(&self) }
}
The problem comes when calling Bar::new, because you are passing &'c Foo<'a>, to something expecting &'b Foo<'b>. Normally, immutable types in Rust are covariant, meaning that &Foo<'a> is implicitly convertable to &Foo<'b> whenever 'b is a shorter lifetime than 'a. Without the Cell, &'c Foo<'a> converts to &'c Foo<'c>, and is passed to Bar::new wiht 'b = 'c, so there is no problem.
However, Cell adds interior mutability to Foo, which means that it is no longer safe to be covariant. This is because Bar could potentially try to assign a shorter lived 'b reference back into the original Foo, but Foo requires that all of the references it holds are valid for the longer lifetime 'a. Therefore, interior mutability makes &Foo invariant, meaning you can no longer shorten the lifetime parameter implicitly.

What does it mean for a trait to have a lifetime parameter?

I understand how lifetime parameters apply to functions and structs, but what does it mean for a trait to have a lifetime parameter? Is it a shortcut to introduce a lifetime parameter to its methods, or is it something else?
If you have a trait with a lifetime bound, then implementors of the trait can participate in the same lifetime. Concretely, this allows you to store references with that lifetime. It is not a shortcut for specifying lifetimes on member methods, and difficulty and confusing error messages lie that way!
trait Keeper<'a> {
fn save(&mut self, v: &'a u8);
fn restore(&self) -> &'a u8;
}
struct SimpleKeeper<'a> {
val: &'a u8,
}
impl<'a> Keeper<'a> for SimpleKeeper<'a> {
fn save(&mut self, v: &'a u8) {
self.val = v
}
fn restore(&self) -> &'a u8 {
self.val
}
}
Note how both the struct and the trait are parameterized on a lifetime, and that lifetime is the same.
What would the non-trait versions of save() and restore() look like for SimpleKeeper<'a>?
Very similar, actually. The important part is that the struct stores the reference itself, so it needs to have a lifetime parameter for the values inside.
struct SimpleKeeper<'a> {
val: &'a u8,
}
impl<'a> SimpleKeeper<'a> {
fn save(&mut self, v: &'a u8) {
self.val = v
}
fn restore(&self) -> &'a u8 {
self.val
}
}
And would they mean exactly the same thing as the the trait version?
Yep!

Resources