When &self has different lifetime than the struct - rust

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

Related

Lifetime and associated types

I have this enum:
enum Node<T> {
Leaf(T),
Children(Vec<Node<T>>),
}
And want to implement the Iterator trait for Node.
I created this struct and tried to implement the IntoIterator trait:
struct NodeIter<'a, T>{
children: &'a [Node<T>],
parent: Option<&'a Node<T>>,
}
impl<'a, T> IntoIterator for Node<T> {
type Item = T;
type IntoIter = NodeIter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
todo!()
}
}
I can not figure out the correct lifetime specifiers, I end up getting this error:
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> src/tree_my.rs:44:6
|
44 | impl<'a, T> IntoIterator for Node<T> {
| ^^ unconstrained lifetime parameter
I am new to Rust and I am not sure if I am doing it wrong or if it is not possible. Because I have read about similar problems. The problem seems to have something to do with traits (IntoIterator in my case) and associated types. I also read something about GAT.
Maybe someone could explains this problem and how one would solve it.
Rust Playground
IntoIterator::into_iter consumes its argument. This means that once you've called node.into_iter() the node no longer exists, but it looks like you want your NodeIter to keep references to node which is impossible since it's no longer around.
You will need to either change NodeIter to take ownership of the original Node so that NodeIter can keep the Node alive for as long as it needs it, or implement IntoIter for references to Node (which will consume the reference, but keep the original Node intact):
enum Node<T> {
Leaf(T),
Children(Vec<Node<T>>),
}
struct NodeIter<'a, T>{
children: &'a [Node<T>],
parent: Option<&'a Node<T>>,
}
impl<'a, T> Iterator for NodeIter<'a, T> {
type Item = T;
fn next (&mut self) -> Option<Self::Item> {
todo!();
}
}
impl<'a, T> IntoIterator for &'a Node<T> {
type Item = T;
type IntoIter = NodeIter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
todo!()
}
}
Playground

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

Lifetime of self embedded in Self, not &'a self

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.

Wrong trait chosen based on type parameter

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.

Trait to store structs with different generic parameters

I need to store in the same Vec instances of the same struct, but with different generic parameters. This is the struct definition:
struct Struct<'a, T: 'a> {
items: Vec<&'a T>
}
The struct has a method returning an iterator to a type that does not depend on the generic type parameter T:
impl<'a, T: 'a> Struct<'a, T> {
fn iter(&self) -> slice::Iter<&i32> {
unimplemented!()
}
}
I need to access this method for those different structs in the vector, so I've implemented this trait:
type Iter<'a> = Iterator<Item=&'a i32>;
trait Trait {
fn iter(&self) -> Box<Iter>;
}
And I've implemented the trait for Struct:
impl<'a, T: 'a> Trait for Struct<'a, T> {
fn iter(&self) -> Box<Iter> {
Box::new(self.iter())
}
}
But the compiler complains:
<anon>:21:9: 21:30 error: type mismatch resolving `<core::slice::Iter<'_, &i32> as core::iter::Iterator>::Item == &i32`:
expected &-ptr,
found i32 [E0271]
<anon>:21 Box::new(self.iter())
^~~~~~~~~~~~~~~~~~~~~
<anon>:21:9: 21:30 help: see the detailed explanation for E0271
<anon>:21:9: 21:30 note: required for the cast to the object type `core::iter::Iterator<Item=&i32> + 'static`
<anon>:21 Box::new(self.iter())
^~~~~~~~~~~~~~~~~~~~~
I've tried different possibilities for lifetime parameters in the trait, but none of them work. How can I make this work?
Rust Playground snippet
Edit
As pointed out by #MatthieuM. one problem is that the type alias is not working properly. Here's another example demonstrating this:
use std::slice;
type Iter<'a> = Iterator<Item=&'a i32>;
struct Struct<'a> { _phantom: std::marker::PhantomData<&'a i32> }
impl<'a> Struct<'a> {
fn direct<'b>(i: &'b slice::Iter<'a, i32>) -> &'b Iterator<Item=&'a i32>
{ i }
fn aliased<'b>(i: &'b slice::Iter<'a, i32>) -> &'b Iter<'a>
{ i }
}
In this example, direct compiles, but aliased not, with the error:
<anon>:12:7: 12:8 error: the type `core::slice::Iter<'a, i32>` does not fulfill the required lifetime
<anon>:12 { i }
^
note: type must outlive the static lifetime
But they seem to be the same thing. What's happening?
Problem 1 — slice::Iter<T> has an Iterator::Item of &T, thus your reference levels are mismatched. Change your method to be
fn iter(&self) -> slice::Iter<i32>
Problem 2 — Box<SomeTrait> is equivalent to Box<SomeTrait + 'static>, but your iterator does not live for the 'static lifetime. You need to explicitly bring in a lifetime:
Box<SomeTrait + 'a>
Problem 3 — I don't understand how you can create a type alias for a trait, that seems very odd. You probably don't want it anyway. Instead, create a type alias for the whole boxed version:
type IterBox<'a> = Box<Iterator<Item=&'a i32> + 'a>;
Problem 4 — Rearrange your main so that references will live long enough and add mutability:
fn main() {
let i = 3;
let v = vec![&i];
let mut traits : Vec<Box<Trait>> = Vec::new();
traits.push(Box::new(Struct{ items: v }));
}
All together:
use std::slice;
type IterBox<'a> = Box<Iterator<Item=&'a i32> + 'a>;
trait Trait {
fn iter<'a>(&'a self) -> IterBox;
}
struct Struct<'a, T: 'a> {
items: Vec<&'a T>
}
impl<'a, T: 'a> Struct<'a, T> {
fn iter(&self) -> slice::Iter<i32> {
unimplemented!()
}
}
impl<'a, T: 'a> Trait for Struct<'a, T> {
fn iter(&self) -> IterBox {
Box::new(self.iter())
}
}
fn main() {
let i = 3;
let v = vec![&i];
let mut traits: Vec<Box<Trait>> = Vec::new();
traits.push(Box::new(Struct { items: v }));
}

Resources