Trait associated type lifetime and self - rust

I have a struct that wraps a std::cell::Ref and provides access by reference to the underlying value. Something like this:
use std::cell::Ref;
struct IntAccess<'a> {
i: Ref<'a, i32>,
}
impl IntAccess<'_> {
fn get(&self) -> &i32 {
&self.i
}
}
This works fine. Since I have multiple structs like this, I'd like to define a common trait:
trait Access {
type Item;
fn get(&self) -> Self::Item;
}
However, I get into trouble when trying to implement Access for IntAccess:
impl<'a> Access for IntAccess<'a> {
type Item = &'a i32;
fn get(&self) -> Self::Item {
&self.i
}
}
It fails with the following error:
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/main.rs:23:9
|
23 | &self.i
| ^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src/main.rs:22:12
|
22 | fn get(&self) -> Self::Item {
| ^^^^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:23:9
|
23 | &self.i
| ^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src/main.rs:19:6
|
19 | impl<'a> Access for IntAccess<'a> {
| ^^
note: ...so that the types are compatible
--> src/main.rs:22:33
|
22 | fn get(&self) -> Self::Item {
| _________________________________^
23 | | &self.i
24 | | }
| |_____^
= note: expected `<IntAccess<'a> as Access>`
found `<IntAccess<'_> as Access>`
I think I kind of get what the compiler is trying to tell me: I'm trying to borrow self.i which has an anonymous lifetime unrelated to the lifetime of Self::Item ('a). So what seems to be needed is to somehow tie the lifetime of self in get to the lifetime 'a. Is there a way to do this?
I have to admit that I don't fully grasp the problem. Since I pass the lifetime 'a to the Ref, and Ref internally stores a reference with this lifetime, it seems to me that it should somehow be possible to get a reference with lifetime 'a out of it without having to explicitly tie self to this lifetime as well. So what am I missing here?

Your understanding is correct. About your doubt, let's name the lifetimes for easier debugging:
impl<'a> Access for IntAccess<'a> {
type Item = &'a i32;
fn get<'b>(&'b self) -> Self::Item {
&self.i
}
}
self has the type &'b IntAccess<'a>. 'b is shorter than or equal to 'a - that is required for self to be well-formed, i.e. able to exist (otherwise, it would contain a dangling reference).
For that reason, we cannot borrow self for more than 'b - or we could do something like:
let v: IntAccess<'a>;
let inner: &'a i32 = {
let r: &'b IntAccess<'a> = &v;
<IntAccess<'a> as Access>::get(r)
}
let mut_r: &mut IntAccess<'a> = &mut v;
And we have both a shared and a mutable reference to (parts of) inner!
Your problem cannot be solved fully without Generic Associated Types. They allow you to parameterize an associated type by a lifetime, making it able to express "I want to return this associated type tied to the lifetime of self":
#![feature(generic_associated_types)]
trait Access {
type Item<'a>
where
Self: 'a;
fn get<'a>(&'a self) -> Self::Item<'a>;
// Or, with lifetime elision:
// fn get(&self) -> Self::Item<'_>;
}
impl<'a> Access for IntAccess<'a> {
type Item<'b> = &'b i32
where
'a: 'b;
fn get<'b>(&'b self) -> Self::Item<'b> {
&self.i
}
}
Playground.
Can we do that on stable? We can emulate that. Instead of implementing Access for IntAccess itself, we will implement it for a reference to it!
trait Access {
type Item;
fn get(self) -> Self::Item;
}
impl<'a, 'b> Access for &'b IntAccess<'a> {
type Item = &'b i32;
fn get(self) -> &'b i32 {
&self.i
}
}
Playground
This does not always work, and thus is not a full replacement to GATs, but is good enough in this case.

Related

Avoid lifetime constraints on trait associated types

tl;dr:
Is there any way to remove the lifetime declaration from ObjectInner and move it to the foo method?
trait ObjectTrait {
type Input;
fn foo(&mut self, input: &mut Self::Input);
}
struct ObjectInner<'a> {
phantom: PhantomData<&'a ()>,
}
impl<'a> ObjectTrait for ObjectInner<'a>
{
type Input = Mut<'a>;
fn foo(&mut self, _input: &mut Self::Input) {}
}
Suppose I have the following trait definition (with an associated type Input):
trait ObjectTrait {
type Input;
fn foo(&mut self, input: &mut Self::Input);
}
I'm interested in implementing this trait for an object such that the type used for Input could potentially take a lifetime.
impl ObjectTrait for ObjectInner
{
type Input = Mut<'a>;
fn foo(&mut self, _input: &mut Self::Input) {}
}
This won't compile since lifetime 'a hasn't been defined. It makes sense, and it provides two suggestions:
error[E0261]: use of undeclared lifetime name `'a`
--> src/main.rs:13:22
|
13 | type Input = Mut<'a>;
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'a` here
|
13 | type Input<'a> = Mut<'a>;
| ++++
help: consider introducing lifetime `'a` here
|
11 | impl<'a> ObjectTrait for ObjectInner
| ++++
Define the lifetime either in the type or in the impl.
Defining them on the type is out of the question since this requires changing the trait definition, which doesn't make sense for users of the trait without use for this lifetime.
Defining it on the impl makes more sense, and if done naively:
impl<'a> ObjectTrait for ObjectInner
{
type Input = Mut<'a>;
fn foo(&mut self, _input: &mut Self::Input) {}
}
I get the following error/help message:
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> src/main.rs:15:6
|
15 | impl<'a> ObjectTrait for ObjectInner
| ^^ unconstrained lifetime parameter
I need to put a constraint on the lifetime. The only way I know how to do it is by extending the ObjectInner to have the following definition:
struct ObjectInner<'a> {
phantom: PhantomData<&'a ()>,
}
impl<'a> ObjectTrait for ObjectInner<'a>
{
type Input = Mut<'a>;
fn foo(&mut self, _input: &mut Self::Input) {}
}
This already works and is the best solution I've found so far.
I wonder if there is a way to move this constraint outside of the struct definition to the declaration of the foo method. I feel this should be possible, given that if I wouldn't be implementing a trait, I could make this with:
impl ObjectInner {
fn bar<'a>(&mut self, input: &mut Mut<'a>) {}
}

Damned if you do, damned if you don't: Rust compiler complains regardless whether there's a lifetime parameter or not

I am trying to decide whether I should add a lifetime parameter to my impls, but it seems I'm in a "damned if you do, damned if you don't" situation because the compiler complains regardless whether there's a lifetime parameter or not.
pub struct TurtleRef<'a> {
t: &'a BorrowedTurtle<'a>,
}
impl TurtleRef<'_> {
pub fn borrowed_turtle(&self) -> BorrowedTurtle {
*self.t
}
pub fn new(r: Turtle) -> TurtleRef {
TurtleRef{t: &BorrowedTurtle{ t:r}}
}
}
pub struct BorrowedTurtle<'a> {
t: Turtle<'a>,
}
impl<'a> std::ops::Deref for BorrowedTurtle<'_> {
type Target = Turtle<'a>;
fn deref(&self) -> &Self::Target {
&self.t
}
}
impl<'a> std::ops::DerefMut for BorrowedTurtle<'_> {
type Target = Turtle<'a>;
fn deref_mut(&mut self) -> &mut Self::Target {
&self.t
}
}
pub struct Turtle<'a> {
children: Vec<Turtle<'a>>,
}
Turtle has more fields, but I removed them for simplicity. You can see the code snippet here. The code throws the error
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> src/campus.rs:54:6
|
54 | impl<'a> std::ops::Deref for BorrowedTurtle<'_> {
| ^^ unconstrained lifetime parameter
No problem, I'll just remove the parameter since it's causing such a fuss. But after removing it, I get a whole bunch of new errors:
error[E0261]: use of undeclared lifetime name `'a`
--> src/campus.rs:55:26
|
55 | type Target = Turtle<'a>;
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'a` here
|
54 | impl<'a> std::ops::Deref for BorrowedTurtle<'_> {
| ^^^^
help: consider introducing lifetime `'a` here
|
55 | type Target<'a> = Turtle<'a>;
| ^^^^
Whatever you say, I'll just go ahead and add that parameter to target. But now I get yet another error:
error[E0658]: generic associated types are unstable
--> src/campus.rs:55:5
|
55 | type Target<'a> = Turtle<'a>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
So no matter what I do, it seems I run into a major error. How do I stop these errors without starting over from scratch? I'd like to keep the impls, structs, and deref functions, so the only thing I should change is their implementation.
On another note, I get the error
error[E0437]: type `Target` is not a member of trait `std::ops::DerefMut`
--> src/campus.rs:64:5
|
64 | type Target = Turtle<'a>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `std::ops::DerefMut`
because Turtle doesn't implement DerefMut, and in fact Turtle should not implement DerefMut. Is there a slight modification of Turtle which results in something that already implements DerefMut?
There are a couple of issues here. Firstly:
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> src/campus.rs:54:6
|
54 | impl<'a> std::ops::Deref for BorrowedTurtle<'_> {
| ^^ unconstrained lifetime parameter
You either use an anonymous lifetime or you don't. Here, you declare the 'a, so use it:
impl<'a> std::ops::Deref for BorrowedTurtle<'a> {
To use an elided lifetime, you don't have to declare it:
impl std::ops::Deref for BorrowedTurtle<'_> {
However, here you have to refer to the lifetime in Target, so you cannot elide it.
Second:
error[E0437]: type `Target` is not a member of trait `std::ops::DerefMut`
--> src/lib.rs:28:5
|
28 | type Target = Turtle<'a>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `std::ops::DerefMut`
DerefMut does not have a Target member because it reuses that from its supertrait, Deref. This is to ensure that items must Deref and DerefMut to the same Target:
impl<'a> std::ops::Deref for BorrowedTurtle<'a> {
type Target = Turtle<'a>;
fn deref(&self) -> &Self::Target {
&self.t
}
}
impl std::ops::DerefMut for BorrowedTurtle<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.t
}
}
Lastly, you will now get errors that 'a is not used:
error[E0392]: parameter `'a` is never used
--> src/lib.rs:15:27
|
15 | pub struct BorrowedTurtle<'a> {
| ^^ unused parameter
|
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
This is because you have a couple of recursive types where the lifetime isn't actually being used:
// 'a isn't actually used for anything
pub struct Turtle<'a> {
children: Vec<Turtle<'a>>,
}
pub struct BorrowedTurtle<'a> {
t: Turtle<'a>,
}
I will assume that for the purpose of this answer you omitted other relevant fields that use the 'a, so that's all!
Since DerefMut inherit from Deref, you don't have to specify Target, pub trait DerefMut: Deref { use the Target define in Deref implementation.
Deref trait is very special, it can't really be use by "normal" user, almost only std can implement it for new type.
This is because it's borrow self and return a reference of "something else" problem is this something else can't be temporary, std use it control over rust ecosystem to be able to do that for example Vec implementation:
impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
fn deref_mut(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
}
}
as you can see slice is a "fat pointer" so it doesn't need more than a reference to be valid, you can almost only implement Deref to return Target for type like slice.
Another example is for PathBuf:
impl ops::Deref for PathBuf {
type Target = Path;
#[inline]
fn deref(&self) -> &Path {
Path::new(&self.inner)
}
}
Here it's even more clear Path::new create a fat pointer. So, Target can't be something else that something that can't be self contained or already exist in your Self.
As the documentation said:
Because of this, Deref should only be implemented for smart pointers to avoid confusion.
I think what you really want is to implement Borrow. All that said... here a working code:
impl<'a> std::ops::Deref for BorrowedTurtle<'a> {
type Target = Turtle<'a>;
fn deref(&self) -> &Self::Target {
&self.t
}
}
impl std::ops::DerefMut for BorrowedTurtle<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.t
}
}
Do as you wish.

How to get a reference to a struct with lifetime annotations from a trait object? [duplicate]

I ran into a lifetime problem with a little game. The below code represents a very boiled down version of the update loop.
I need the container mutable reference to get references to other game objects or to create new ones or trigger a functionality.
For that reason, I need the Any trait to be able to cast the trait to a struct, so in my GameObj trait I added an as_any method, but this resulted in a lifetime issue.
use std::any::Any;
trait GameObj<'a> {
fn as_any<'b>(&'b self) -> &'b (dyn Any + 'a);
fn update(&mut self, cont: &mut container);
}
struct object<'a> {
content: &'a String,
}
impl<'a> GameObj<'a> for object<'a> {
fn as_any<'b>(&'b self) -> &'b (dyn Any + 'a) {
return self;
}
fn update(&mut self, cont: &mut container) {
let val = cont.get_obj().unwrap();
let any = val.as_any();
}
}
struct container<'a> {
data: Vec<Box<dyn GameObj<'a> + 'a>>,
}
impl<'a> container<'a> {
fn get_obj<'b>(&'b self) -> Option<&'b Box<dyn GameObj<'a> + 'a>> {
return Some(&self.data[0]);
}
}
pub fn main() {
let a = String::from("hallo");
let b = String::from("asdf");
{
let abc = object { content: &a };
let def = object { content: &b };
let mut cont = container { data: Vec::new() };
cont.data.push(Box::new(abc));
cont.data.push(Box::new(def));
loop {
for i in 0..cont.data.len() {
let mut obj = cont.data.remove(0);
obj.update(&mut cont);
cont.data.insert(i, obj);
}
}
}
}
playground
When I try to build the code, it results in the following error message.
If I comment out/delete let any = val.as_any(); in the update function it compiles fine.
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/main.rs:18:24
|
18 | let val = cont.get_obj().unwrap();
| ^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #3 defined on the method body at 17:5...
--> src/main.rs:17:5
|
17 | / fn update(&mut self, cont: &mut container) {
18 | | let val = cont.get_obj().unwrap();
19 | | let any = val.as_any();
20 | | }
| |_____^
= note: ...so that the types are compatible:
expected &container<'_>
found &container<'_>
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the declared lifetime parameter bounds are satisfied
--> src/main.rs:19:23
|
19 | let any = val.as_any();
| ^^^^^^
How I can make this work without using 'static, or why is this impossible?
Any is declared trait Any: 'static and can only store 'static types. So in order to make dyn Any + 'a a well-formed type, your as_any method was given an implicit 'a: 'static bound, leading to the lifetime error you showed.
If not for this restriction, you would be able to break safety by putting in an 'a type into an Any and getting out a 'static type, because TypeId can’t tell the difference—lifetimes are erased during compilation. See the discussion on RFC 1849 for more information.
You should think more carefully about why you want to use Any. It’s almost never what you actually want. Perhaps something as simple as an enum type of all the different object types you might want to store would satisfy your use case better?
If you really want to use Any, then you’ll need to find a way to make your types 'static. Rc (or Arc, if threads are involved) is often helpful for this purpose; for example, you could have your object store Rc<String> (or better, Rc<str>) instead of &'a String.

cannot infer an appropriate lifetime for lifetime parameter with multiple references with the same lifetime inside a struct [E0495]

I had gotten an error in my code about lifetime inferrence, and I have been able to reduce the code to the following:
use std::collections::HashMap;
struct A<'a> {
x: &'a mut HashMap<&'a str, i32>,
}
impl<'a> A<'a> {
fn new(x: &'a mut HashMap<&'a str, i32>) -> Self {
Self { x }
}
fn test(&mut self) {
let a = A::new(self.x);
}
}
fn main() {
}
The error that results from this is
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/main.rs:13:17
|
13 | let a = A::new(self.x);
| ^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 12:5...
--> src/main.rs:12:5
|
12 | / fn test(&mut self) {
13 | | let a = A::new(self.x);
14 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:13:24
|
13 | let a = A::new(self.x);
| ^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 7:6...
--> src/main.rs:7:6
|
7 | impl<'a> A<'a> {
| ^^
note: ...so that the expression is assignable
--> src/main.rs:13:24
|
13 | let a = A::new(self.x);
| ^^^^^^
= note: expected `&mut std::collections::HashMap<&str, i32>`
found `&mut std::collections::HashMap<&'a str, i32>`
I do not understand what is the error in this case, but I did find that if I add a lifetime 'b to struct A, such that the str reference in the HashMap has a lifetime of 'b, the codes does compile. Here is how the code looks like after the aforementioned change:
use std::collections::HashMap;
struct A<'a, 'b> {
x: &'a mut HashMap<&'b str, i32>,
}
impl<'a, 'b> A<'a, 'b> {
fn new(x: &'a mut HashMap<&'b str, i32>) -> Self {
Self { x }
}
fn test(&mut self) {
let a = A::new(self.x);
}
}
fn main() {
}
However, I have no idea why that change works. To my understanding, having both lifetimes be 'a means that A must live as long as the HashMap, and the HashMap must live as long as the &strs that are used as its keys, which I see no issue with. I also do not see how the change adds any additional information for the compiler. Can anyone please shed some light for me on this situation?
Change the A::test() function into
fn test(&'a mut self) { // Add lifetime specification
let a = A::new(self.x);
}
and it should work.
The compiler said it cannot infer lifetime for A::new(), and the first note mentioned "anonymous lifetime", that means the compiler doesn't know the lifetime of self.x in A::new(self.x). So we just need to tell the compiler that self has a lifetime of 'a.

A smart constructor for an iterator with a reference to a closure inside

Consider the following code for a (greatly simplified) iterator with a reference to a closure inside:
struct IteratorState<'a, T: 'a + Fn(i32) -> i32> {
closure: &'a T,
}
impl<'a, T: 'a + Fn(i32) -> i32> Iterator for IteratorState<'a, T> {
type Item = i32;
fn next(&mut self) -> Option<i32> {
None
}
}
It compiles and I can construct IteratorStates directly. However, I also need a smart constructor to hide some details of the implementation (not shown in the MCVE). The following attempt does not compile:
fn mk_iter<'a, T: Fn(i32) -> i32>(closure: &'a T) -> impl Iterator<Item = i32> {
IteratorState { closure }
}
The error is
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/lib.rs:14:5
|
14 | IteratorState { closure }
| ^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 13:1...
--> src/lib.rs:13:1
|
13 | fn mk_iter<'a, T: Fn(i32) -> i32>(closure: &'a T) -> impl Iterator<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:14:21
|
14 | IteratorState { closure }
| ^^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that return value is valid for the call
--> src/lib.rs:13:54
|
13 | fn mk_iter<'a, T: Fn(i32) -> i32>(closure: &'a T) -> impl Iterator<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
I think I understand what the problem is: there's no guarantee that constructed IteratorState won't outlive the contained reference (please correct me if I got this wrong), but I'm not quite sure how to fix it.
The impl Trait syntax supports adding lifetimes to the return type:
fn mk_iter<'a, T: Fn(i32) -> i32>(closure: &'a T) -> impl Iterator<Item = i32> + 'a {
// here ^^^^
IteratorState {
closure
}
}
(link to playground)

Resources