Reputation: 257
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?
Upvotes: 3
Views: 1188
Reputation: 13618
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!
Upvotes: 5
Reputation: 26765
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.
Upvotes: 0