I am implementing Deref
for a tuple struct in my project which has a String in it.
When dereferenced I want to return a &str from that String but I can't figure out how I can do that.
It would look something like this:
use std::ops::{Deref, DerefMut};
struct Foo(String);
impl Deref for Foo {
type Target = str;
fn deref(&self) -> &str {
&self.0
}
}
impl DerefMut for Foo {
fn deref_mut(&mut self) -> &mut str {
&mut self.0
}
}
Sorry for temporarily having duplicated code; I accidentally pressed post, and this mobile keyboard is not meant to write code.
And how bout the lifetime of the self.0 how is it possible in this example to express to the compiler that it lives after the defer function returns ?
You could annotate them, but the compiler does this automatically:
use std::ops::{Deref, DerefMut};
struct Foo(String);
impl Deref for Foo {
type Target = str;
fn deref<'a>(&'a self) -> &'a str {
&self.0
}
}
impl DerefMut for Foo {
fn deref_mut<'a>(&'a mut self) -> &'a mut str {
&mut self.0
}
}
The more normal way would be to leave them as anonymous lifetimes since you're not doing anything with the lifetimes that would require annotation:
use std::ops::{Deref, DerefMut};
struct Foo(String);
impl Deref for Foo {
type Target = str;
fn deref(&'_ self) -> &'_ str {
&self.0
}
}
impl DerefMut for Foo {
fn deref_mut(&'_ mut self) -> &'_ mut str {
&mut self.0
}
}
Oh i see this makes a lot of sense thanks.
Lastly what would be the difference if type Target=String
and ->&String
was used instead of str?
If we wrote:
type Target = String;
Then our function signature would look like this:
fn deref(&'_ self) -> &'_ String;
Which breaks the guideline that you should usually replace &String
with &str
. But this also makes it so that you can now mutate the String
, in the DerefMut
impl you need to have the same Target
as Deref
so, this would become
fn deref_mut(&'_ mut self) -> &'_ mut String;
With
type Target = &String;
You would have a compiler error since the type
needs to have a lifetime attached to the reference, which could only be acquired from your struct
, but your struct
contains no lifetimes so this would be erroneous.
How can you mutate a &String
from deref its an immutable ref ?
From your previous post, the first suggestion to change the type to String
? Well I only showed the signature for the deref
, deref_mut
would be changed to this:
impl DerefMut for Foo {
fn deref_mut(&'_ mut self) -> &'_ mut String {
&mut self.0
}
}
If you're talking about how a String
becomes &mut str
then just how a String
can coerce into &str
it can coerce into &mut str
.
I see thank you.
Now i noticed that If my target is a str
then *val
would result in a str
which cannot be used without a pointer so I need to do &*val
is there a nicer way do do this without awkward &*
in front of every value?
What I would like to do is simply &val
or *val
only.
This is solved by automatic deref
coercion:
let x = String::from("Abc");
let y = &x; //y: &String
let z: &str = &x; //x: &str
What this shows is that the compiler will automatically produce &U
where T: Deref<Target = U>
and &U
is needed, otherwise it will provide &T
. Notice how on my examples for implementing the Deref
trait, I show it like so:
impl Deref for Foo {
type Target = str;
fn deref(&'_ self) -> &'_ str {
&self.0
}
}
&self.0
would evaluate to &String
, but since the compiler sees I need &str
and String: Deref<Target = str>
it works.
Take a look at
https://doc.rust-lang.org/book/ch15-02-deref.html
In my case I am trying to print the internal value so i have a println!("{}",*val)
and it gives me the error saying size of str cannot be known at compile time
Then unfortunately all I can suggest is to use &*val
unless you are okay with #[derive(Debug)]
-ing your struct
.
Thanks
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.