Shared &str along multiple structs conflicts with Lifetimes - rust

I have the following code:
pub trait Regex: RegexClone {
fn check(&self) -> Result<u32,(/* errors should detail where it fails*/)>;
fn next(&self) -> Option<Box<dyn Regex>>;
}
pub trait RegexClone {
fn regex_clone(&self) -> Box<dyn Regex>;
}
pub struct PatternAnyCharacter<'a>{
string: &'a str
}
impl RegexClone for PatternAnyCharacter<'_> {
fn regex_clone(&self) -> Box<dyn Regex> {
return Box::new(PatternAnyCharacter {string: self.string})
}
}
impl Regex for PatternAnyCharacter<'_> {
fn check(&self) -> Result<u32, ()> {
if self.string.len() > 0 {
return Ok(1);
}
Err(())
}
fn next(&self) -> Option<Box<dyn Regex>> {
None
}
}
The idea is that when i call regex_clone i get a new Box<dyn Regex> with the same &str as member, i supossed that since im only using inmutable references when calling regex_clone it would give me a new struct with the same string slice, since is a reference im not moving anything, however the compiler complains the following:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/lib.rs:63:25
|
63 | return Box::new(PatternAnyCharacter {string: self.string})
| ^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'_` as defined here...
--> src/lib.rs:61:41
|
61 | impl RegexClone for PatternAnyCharacter<'_> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:63:54
|
63 | return Box::new(PatternAnyCharacter {string: self.string})
| ^^^^^^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the types are compatible
--> src/lib.rs:63:16
|
63 | return Box::new(PatternAnyCharacter {string: self.string})
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `Box<(dyn Regex + 'static)>`
found `Box<dyn Regex>`
How can i solve this so i can share the same string slice with multiple struct?
i thought about foregoing the string slice as member entirely and passing it as parameter to check, but hopefully i can avoid it.

You need to define at the trait that the returned dyn Regex can't outlive &self if you want to allow it to borrow from parts of &self.:
pub trait RegexClone {
fn regex_clone<'a>(&'a self) -> Box<dyn Regex + 'a>;
}
(You can also use an anonymous lifetime (Box<dyn Regex + '_>), but this is easier to understand.)
Side note: I don't think "clone" is the right name for such a function.

Related

Trait associated type lifetime and self

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.

Implementing Index for type with a lifetime parameter

I have some types like this, where they each have a lifetime parameter.
use std::marker::PhantomData;
use std::ops::Index;
pub struct Foo<'ctx> {
bars: Vec<Bar<'ctx>>,
phantom: PhantomData<&'ctx ()>,
}
impl Foo<'_> {
pub fn get_bar(&self, index: usize) -> Option<&Bar> {
self.bars.get(index)
}
}
pub struct Bar<'ctx> {
// pretend we are using a context here
phantom: PhantomData<&'ctx ()>,
}
I'd like to implement Index for Foo, but the compiler doesn't like it:
impl <'ctx> Index<usize> for Foo<'ctx> {
type Output = Bar<'ctx>;
fn index(&self, _index: usize) -> &Self::Output {
self.get_bar(_index).unwrap()
}
}
I get this error:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/ir/foo.rs:24:14
|
24 | self.get_bar(_index).unwrap()
| ^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src/ir/foo.rs:23:14
|
23 | fn index(&self, _index: usize) -> &Self::Output {
| ^^^^^
note: ...so that reference does not outlive borrowed content
--> src/ir/foo.rs:24:9
|
24 | self.get_bar(_index).unwrap()
| ^^^^
note: but, the lifetime must be valid for the lifetime `'ctx` as defined here...
--> src/ir/foo.rs:20:7
|
20 | impl <'ctx> Index<usize> for Foo<'ctx> {
| ^^^^
note: ...so that the types are compatible
--> src/ir/foo.rs:23:53
|
23 | fn index(&self, _index: usize) -> &Self::Output {
| _____________________________________________________^
24 | | self.get_bar(_index).unwrap()
25 | | }
| |_____^
= note: expected `<Foo<'ctx> as Index<usize>>`
found `<Foo<'_> as Index<usize>>`
(I see a few similar questions on SO but they all seem to differ in the particulars, namely that the Output type has a lifetime parameter).
This is due to that the rust compiler cannot infer proper lifetimes when there are multiple elided lifetimes. The rust compiler can only take the omitted lifetimes as a same lifetime '_.
The inferred signature of the function get_bar is actually:
pub fn get_bar<'_>(self: &'_ Foo<'_>, index: usize) -> Option<&'_ Bar<'_>>
Note that all '_ refer to the same lifetime, this is obviously not what we need, because we don't have to keep borrowing the value of some Bar during the whole lifetime of 'ctx.
And, the inferred signature of the function index is:
fn index<'_>(self: &'_ Foo<'ctx>, _index: usize) -> &'_ Bar<'ctx>
Which is more generic than the signature of get_bar because it allows the lifetime argument of '_ to be shorter than 'ctx, therefore you cannot call get_bar within the body of index
To make it work, you have to specify an explicit 'ctx, because the elided lifetime '_ has to be the lifetime of the borrowed self.
impl<'ctx> Foo<'ctx> {
pub fn get_bar(&self, index: usize) -> Option<&Bar<'ctx>> {
self.bars.get(index)
}
}
And the signature of get_bar now turns to be:
pub fn get_bar<'_>(self: &'_ Foo<'ctx>, index: usize) -> Option<&'_ Bar<'ctx>>
Then the lifetimes in index could match the lifetimes in get_bar

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 return an iterator over the keys of a HashMap from a trait implementation?

I'm trying to build a simple graph library in Rust. There is a trait Graph that any graph must implement. This trait has only one function at the moment, nodes, which allows iteration of the graph's nodes using a for-in loop.
An implementation of Graph, MapGraph, is a lightweight wrapper around a HashMap. MapGraph must implement the Graph trait method nodes. I'm having problems getting this to work.
Here's the code for Graph:
pub trait Graph<N> {
fn nodes(&self) -> Box<dyn Iterator<Item = &N>>;
}
And here's the code for MapGraph:
use std::collections::HashMap;
use crate::rep::Graph;
pub struct MapGraph<N> {
map: HashMap<N, HashMap<N, ()>>
}
impl<N> MapGraph<N> {
pub fn new(map: HashMap<N, HashMap<N, ()>>) -> Self {
MapGraph { map }
}
}
impl<N> Graph<N> for MapGraph<N> {
fn nodes(&self) -> Box<dyn Iterator<Item=&N>> {
let keys = self.map.keys();
Box::new(keys)
}
}
The compiler gives this error:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:19:29
|
19 | let keys = self.map.keys();
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 18:5...
--> src/lib.rs:18:5
|
18 | / fn nodes(&self) -> Box<dyn Iterator<Item = &N>> {
19 | | let keys = self.map.keys();
20 | |
21 | | Box::new(keys)
22 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:19:20
|
19 | let keys = self.map.keys();
| ^^^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<(dyn std::iter::Iterator<Item = &N> + 'static)>
found std::boxed::Box<dyn std::iter::Iterator<Item = &N>>
I've found other references to this error, but those cases don't seem to look like the one I have here.
I'm using Box because the Graph trait has a function that itself returns a trait. What is the correct way to return an Iterator (or any other trait)? gives this approach as one option, and I haven't been able to implement any of the the others. If there's another way to do this, that would be fine.
What are my options for resolving this specific problem?
It works if you explicitly specify that the trait object (dyn Iterator) that you are returning contains references that are tied to the lifetime of self.
Without adding this bound, the compiler cannot infer from the function signature that the iterator cannot be used after self is moved or destroyed. Because the compiler cannot infer this, it cannot safely use self.map.keys() in the function's output.
Working example with this bound added:
pub trait Graph<N> {
fn nodes<'a>(&'a self) -> Box<dyn Iterator<Item = &N> + 'a>;
}
use std::collections::HashMap;
pub struct MapGraph<N> {
map: HashMap<N, HashMap<N, ()>>,
}
impl<N> MapGraph<N> {
pub fn new(map: HashMap<N, HashMap<N, ()>>) -> Self {
MapGraph { map }
}
}
impl<N> Graph<N> for MapGraph<N> {
fn nodes<'a>(&'a self) -> Box<dyn Iterator<Item = &N> + 'a> {
let keys = self.map.keys();
Box::new(keys)
}
}
Playground
I had thought that a bound of Item = &'a N would also be required, but I guess that's already covered by the "+ 'a"...
N.B. that to make sense of an error like:
expected std::boxed::Box<(dyn std::iter::Iterator<Item = &N> + 'static)>
found std::boxed::Box<dyn std::iter::Iterator<Item = &N>>
you have to understand that the compiler, for ergonomic reasons, automatically adds a + 'static lifetime qualifier to any unqualified trait object. This means that an unqualified Box<dyn MyTrait> is transformed by the compiler into a Box<(dyn MyTrait + 'static)>, which in turn means that the object cannot contain any references except those that last for the lifetime of the entire program.
With this in mind you can see why self.map.keys() does not fit this strict bound, and a more specific explicit bound is required.

casting struct to trait with lifetime got "cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements"

trait BT {
fn get_a(&self) -> &A;
}
#[derive(Debug)]
struct A {
v: i32,
}
impl A {
fn nb(&self) -> Box<BT> {
Box::new(B { a: self })
}
}
#[derive(Debug)]
struct B<'a> {
a: &'a A,
}
impl<'a> BT for B<'a> {
fn get_a(&self) -> &A {
return self.a;
}
}
fn main() {
println!("{:?}", A { v: 32 }.nb().get_a());
}
A has a method to generate a B instance with a reference of A, and B might have many methods access B.a (A's reference in B). If let A.nb() return B instead of BT, the code would work well.
I'm new to Rust. This problem has troubled me all day. What should I do to make this code work? Thanks!
The whole error report:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src\socket\msg\message.rs:53:26
|
53 | Box::new(B{a: self})
| ^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 52:13...
--> src\socket\msg\message.rs:52:13
|
52 | / fn nb(&self) -> Box<BT> {
53 | | Box::new(B{a: self})
54 | | }
| |_____________^
note: ...so that reference does not outlive borrowed content
--> src\socket\msg\message.rs:53:31
|
53 | Box::new(B{a: self})
| ^^^^
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<socket::msg::message::test::test::BT + 'static>
found std::boxed::Box<socket::msg::message::test::test::BT>
The default lifetime of a trait object is 'static. You need to add an explicit lifetime bound to the trait object returned by nb() function:
impl A {
fn nb<'s>(&'s self) -> Box<BT+'s> {
Box::new(B{a: self})
}
}
Inference of Trait Object Lifetimes

Resources