I've reduced my problem to the following code:
struct Struct<'a, 'b, T> {
a: &'a T,
b: &'b T,
}
trait Trait<'a, 'b, T> {
fn a(&self) -> &'a T;
fn b(&self) -> &'b T;
}
impl<'a, 'b, T> Trait<'a, 'b, T> for Struct<'a, 'b, T> {
fn a(&self) -> &'a T {
self.a
}
fn b(&self) -> &'b T {
self.b
}
}
struct Confused<T> {
field: T,
}
impl<T> Confused<T> {
fn foo<'a, 'b>(&'a self, param: &Struct<'a, 'b, T>) -> &'a T {
param.b();
param.a()
}
fn bar<'a, 'b, U: Trait<'a, 'b, T>>(&'a self, param: &U) -> &'a T {
param.b();
param.a()
}
}
The function foo is okay, but when I replace the concrete type Struct<'a, 'b, T> with a generic type U: Trait<'a, 'b, T>, I get the following error:
error[E0309]: the parameter type `T` may not live long enough
--> src/lib.rs:31:15
|
24 | impl<T> Confused<T> {
| - help: consider adding an explicit lifetime bound `T: 'b`...
...
31 | param.b();
| ^
|
note: ...so that the reference type `&'b T` does not outlive the data it points at
--> src/lib.rs:31:15
|
31 | param.b();
| ^
The suggestion to add the bound T: 'b doesn't make sense to me, since 'b is a parameter to bar(). How can I fix bar() to accept any implementation of Trait<'a, 'b, T> as a parameter?
When you write a generic type such as:
struct Foo<'a, T> {
a: &'a T,
}
Rust automatically adds an implicit restriction of the type T: 'a, because your reference to T cannot live longer than T itself. This is automatic because your type would not work without it.
But when you do something like:
impl<T> Foo {
fn bar<'a, 'b>() -> &'a T {/*...*/}
}
there is an automatic T: 'a but not a T: 'b because there is no &'b T anywhere.
The solution is to add those constraints by yourself. In your code it would be something like this:
impl<T> Confused<T> {
fn bar<'a, 'b, U: Trait<'a, 'b, T>>(&'a self, param: &U) -> &'a T
where
T: 'b, //<--- here!
{
param.b();
param.a()
}
}
Related
On this example
use std::marker::PhantomData;
pub struct A<'a, T> {
elements: Vec<B<'a, T>>
}
pub struct B<'a, T> {
_phantom: PhantomData<&'a T>
}
impl<'a, T> A<'a, T> {
pub fn iter(& self) -> Iter<'a, T> {
Iter {
iter: self.elements.iter(),
}
}
}
pub struct Iter<'a, T> {
iter: std::slice::Iter<'a, B<'a, T>>,
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e246ef19b9ae5f1d405bde7c59d456d7
I get
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/lib.rs:14:24
|
14 | iter: self.elements.iter(),
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src/lib.rs:12:17
//...
I know why this happens: the elements in self.elements lives as long as &self, so it cannot possibly create an Iter with lifetime a. The easy solution would be to do
pub fn iter(&'a self) -> Iter<'a, T> {
Iter {
iter: self.elements.iter(),
}
}
but then I'm forced to borrow the &self for its entire existence which leads me to other problems. Whatis the easiest solution here?
Your Iter implementation is over-constrained; you have two unrelated lifetimes that are required to be the same. You should separate them:
impl<'a, T> A<'a, T> {
pub fn iter(&self) -> Iter<'a, '_, T> {
Iter {
iter: self.elements.iter(),
}
}
}
pub struct Iter<'a, 'b, T> {
iter: std::slice::Iter<'b, B<'a, T>>,
}
That way, even if 'a is invariant, you don't run into issues with linking that lifetime to self. See it working on the playground (with additional tests).
Below I have
impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
fn as_poly_iterator(
&self
) -> Result<
which shouldn't need &'a self because the 'a already comes from MyPolynomial<'a, T>. Also, I should pass &'a[T] in PolyIterator::new in the line
let iterator = PolyIterator::new(self.coefficients.as_life_ref());
but I'm getting an error saying that it wants a &'a (dyn Mem<'a, T> + 'a) which I have no idea why.
pub trait Mem<'r, T>
{
fn as_life_ref(&'r self) -> &'r [T];
}
pub struct PolyIterator<'a, T> {
coefficients: &'a [T]
}
impl<'a, T> PolyIterator<'a, T> {
pub fn new(coefficients: &'a[T]) -> PolyIterator<'a, T> {
todo!()
}
}
pub struct MyPolynomial<'a, T> {
coefficients: Box<dyn Mem<'a, T> + 'a>,
}
pub trait AsPolyIterator<'a, T> {
fn as_poly_iterator(&'a self) -> Result<PolyIterator<'a, T>, ()>;
}
impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
fn as_poly_iterator(
&self
) -> Result<
PolyIterator<'a, T>,
(),
> {
let iterator = PolyIterator::new(self.coefficients.as_life_ref());
todo!()
}
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c3e657136252b96cd5aca91efeaea56f
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:31:54
|
31 | let iterator = PolyIterator::new(self.coefficients.as_life_ref());
| ^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src/lib.rs:26:3
|
26 | &self
| ^^^^^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:31:36
|
31 | let iterator = PolyIterator::new(self.coefficients.as_life_ref());
| ^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src/lib.rs:24:6
|
24 | impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
| ^^
note: ...so that the types are compatible
--> src/lib.rs:31:54
|
31 | let iterator = PolyIterator::new(self.coefficients.as_life_ref());
| ^^^^^^^^^^^
= note: expected `&'a (dyn Mem<'a, T> + 'a)`
found `&(dyn Mem<'a, T> + 'a)`
Your trait definition and implementation do not line up:
pub trait AsPolyIterator<'a, T> {
fn as_poly_iterator(&'a self) -> Result<PolyIterator<'a, T>, ()>;
}
impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
fn as_poly_iterator(&self) -> Result<PolyIterator<'a, T>, ()> { ... }
}
The trait has PolyIterator bound to self, while the implementation has it bound elsewhere, these are not compatible.
It should definitely be &'a self since the PolyIterator is derived from self.coefficients, but you should use a different lifetime 'b for MyPolynomial to avoid over-constraining:
impl<'a, 'b, T> AsPolyIterator<'a, T> for MyPolynomial<'b, T> where 'a: 'b {
fn as_poly_iterator(&'a self) -> Result<PolyIterator<'a, T>, ()> { ... }
}
Mind the where 'a: 'b since that ensures the lifetime 'b is larger than 'a. See it working on the playground.
I tried to implement some graph algorithms on generic graphs. For that, I defined two graph traits which would return either a generic trait (having set-operations) SetGraph or an IntoIterator used to iterate over the nodes NeighborhoodIteratorGraph.
pub trait NeighborhoodIteratorGraph<'a> {
//which into_iterator do we have?
type IntoIter: 'a + std::iter::IntoIterator<Item = usize>;
fn get_neighborhood_iterator(&'a self, index: usize) -> Self::IntoIter;
}
pub trait SetGraph<'a>
where
&'a Self::S: IntoIterator<Item = usize>,
Self::S: 'a,
{
type S;
fn get_neighborhood(&'a self, index: usize) -> &'a Self::S;
}
Because one is usually able to iterate over sets, I also implemented NeighborhoodIteratorGraph for all SetGraph which are able to iterate over their sets.
impl<'a, G> NeighborhoodIteratorGraph<'a> for G
where
G: SetGraph<'a>,
&'a G::S: IntoIterator<Item = usize>,
{
type IntoIter = &'a G::S;
fn get_neighborhood_iterator(&'a self, index: usize) -> Self::IntoIter {
self.get_neighborhood(index)
}
}
I needed to add a lifetime to NeighborrhoodIteratorGraph otherwise the compiler would tell me my implementation would have an unbounded lifetime.
However I quicky run into problems with these lifetimes and I get an error for the following code:
struct Foo<'a, G: NeighborhoodIteratorGraph<'a>> {
graph: G,
//otherwise we get an error because 'a wouldn't be used
_marker: std::marker::PhantomData<&'a G>,
}
impl<'a, G: NeighborhoodIteratorGraph<'a>> Foo<'a, G> {
pub fn find_matching_for<I>(&mut self, nodes: I) -> bool
where
I: std::iter::IntoIterator<Item = usize>,
{
for node in self.graph.get_neighborhood_iterator(3) {}
return true;
}
}
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
It seems that the PhantomData field is more a hack and I can't find a way in which I get a set refernce which can be seen as a IntoIterator object.
Here is the Rust Playground of the problem.
Full error message:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:38:32
|
38 | for node in self.graph.get_neighborhood_iterator(3) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 34:5...
--> src/lib.rs:34:5
|
34 | / pub fn find_matching_for<I>(&mut self, nodes: I) -> bool
35 | | where
36 | | I: std::iter::IntoIterator<Item = usize>,
| |_________________________________________________^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:38:21
|
38 | for node in self.graph.get_neighborhood_iterator(3) {}
| ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 33:6...
--> src/lib.rs:33:6
|
33 | impl<'a, G: NeighborhoodIteratorGraph<'a>> Foo<'a, G> {
| ^^
note: ...so that the types are compatible
--> src/lib.rs:38:32
|
38 | for node in self.graph.get_neighborhood_iterator(3) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `&'a G`
found `&G`
What you want is a workaround for the lack of generic associated types, which are currently very unstable. Something Like
pub trait NeighborhoodIteratorGraph {
type IntoIter<'a>: std::iter::IntoIterator<Item = usize> + 'a;
fn get_neighborhood_iterator<'b>(&'b self, index: usize) -> Self::IntoIter<'b>;
}
would serve you perfectly if they were stable.
The first thing I did is remove the lifetime bound on NeighborhoodIteratorGraph and add it to the return type:
pub trait NeighborhoodIteratorGraph {
type IntoIter: std::iter::IntoIterator<Item = usize>;
fn get_neighborhood_iterator<'b>(&'b self, index: usize) -> Self::IntoIter
where
Self::IntoIter: 'b;
}
I then removed unnecessary lifetime annotations from SetGraph:
pub trait SetGraph<'a>
where
&'a Self::S: IntoIterator<Item = usize>,
Self::S: 'a,
{
type S;
fn get_neighborhood(&self, index: usize) -> &Self::S;
}
I then changed the blanket impl's signature to match the modified traits, and changed the impl from G to &'a G to properly constrain the lifetime 'a:
impl<'a, G> NeighborhoodIteratorGraph for &'a G
where
G: SetGraph<'a>,
&'a G::S: IntoIterator<Item = usize>,
{
type IntoIter = &'a G::S;
fn get_neighborhood_iterator<'b>(&'b self, index: usize) -> Self::IntoIter
where
Self::IntoIter: 'b,
{
self.get_neighborhood(index)
}
}
Because of those changes I was able to simplify Foo and its impl:
struct Foo<G: NeighborhoodIteratorGraph> {
graph: G,
}
impl<G: NeighborhoodIteratorGraph> Foo<G> {
pub fn find_matching_for<I>(&mut self, nodes: I) -> bool
where
I: std::iter::IntoIterator<Item = usize>,
{
for node in self.graph.get_neighborhood_iterator(3) {}
return true;
}
}
Leaving the compiler output with nothing but dead code warnings. Playground link
I have a binary trait Resolve.
pub trait Resolve<RHS = Self> {
type Output;
fn resolve(self, rhs: RHS) -> Self::Output;
}
I implemented the trait for something trivial where both arguments are taken by reference (self is &'a Foo and rhs is &'b Foo):
struct Foo;
impl <'a, 'b> Resolve<&'b Foo> for &'a Foo {
type Output = Foo;
fn resolve(self, rhs: &'b Foo) -> Self::Output {
unimplemented!()
}
}
If I now write
fn main() {
let a: &Foo = &Foo;
let b = Foo;
a.resolve(&b);
}
it will compile just fine, but if I try to implement it on my struct Signal, it will not work.
pub struct Signal<'a, T> {
ps: Vec<&'a T>,
}
impl<'a, T: Resolve<&'a T, Output = T> + 'a> Signal<'a, T> {
pub fn foo(&mut self) {
let a: &T = &self.ps[0];
let b = &self.ps[1];
a.resolve(b);
}
}
error[E0507]: cannot move out of borrowed content
--> src/main.rs:25:9
|
25 | a.resolve(b);
| ^ cannot move out of borrowed content
How do I get this example working? (playground)
The trait bound on foo only says that T implements Resolve, but you try to call .resolve() on a value of type &T.
To say, instead, that references to T must implement Resolve, you need a higher-ranked trait bound:
impl<'a, T> Signal<'a, T>
where
for<'b> &'b T: Resolve<&'a T, Output = T>,
{
pub fn foo(&mut self) { ... }
}
After thinking about this I came up with a simpler solution that does not rely on HRTB.
impl<'a, T> Signal<'a, T>
where
&'a T: Resolve<&'a T, Output = T> + 'a,
{
pub fn foo(&mut self) {
let a: &T = &self.ps[0];
let b = &self.ps[1];
a.resolve(b);
}
}
This does the same, namely describe, that &T implements Resolve, but without the need of HRTB.
You have to use the where clause for this, but apart from that this is a nice and easy solution.
This snippet does not compile because of a compiler bug:
struct Theory<'a, T: 'a> {
left: &'a T,
}
pub struct Contain<'a, T: 'a, U>
where
&'a T: IntoIterator,
for<'x> <(&'a T) as IntoIterator>::Item: PartialEq<&'x U>,
{
theory: Theory<'a, T>,
right: U,
}
impl<'a, T: 'a, U> Drop for Contain<'a, T, U>
where
&'a T: IntoIterator,
for<'x> <(&'a T) as IntoIterator>::Item: PartialEq<&'x U>,
{
fn drop(&mut self) {
//TODO
}
}
fn main() {}
I need this because I must compare the iterator Items with U; but Item is a reference type, because I call into_iter() in a borrowed collection.
I then tried something like this to work around:
struct Theory<'a, T: 'a> {
left: &'a T,
}
pub struct Contain<'a, 'b: 'a, T: 'a, U: 'b>
where
&'a T: IntoIterator,
<(&'a T) as IntoIterator>::Item: PartialEq<&'b U>,
{
theory: Theory<'a, T>,
right: U,
_marker: ::std::marker::PhantomData<&'b ()>,
}
impl<'a, 'b, T: 'a, U> Drop for Contain<'a, 'b, T, U>
where
&'a T: IntoIterator,
<(&'a T) as IntoIterator>::Item: PartialEq<&'b U>,
{
fn drop(&mut self) {
for left in self.theory.left.into_iter() {
if left == &self.right {
return;
}
}
//handle case where all lefts are different of right
}
}
fn main() {}
But I got a:
cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/main.rs:22:24
|
22 | if left == &self.right {
| ^^^^^^^^^^^
|
How can I iterate over left, then compare each elements with right?
You can simply require the trait bound PartialEq<B>. The methods eq and ne from the trait take all arguments by reference, so there is no reason why requiring PartialEq for a reference to a type.
So this works:
impl<'a, 'b, T: 'a, U> Drop for Contain<'a, 'b, T, U>
where
&'a T: IntoIterator,
<(&'a T) as IntoIterator>::Item: PartialEq<U>, // <-- change 1
{
fn drop(&mut self) {
for left in self.theory.left.into_iter() {
if left == self.right { // <-- change 2
return;
}
}
//handle case where all lefts are different of right
}
}