'Newtype pattern error: cannot move out of dereference of
I want to create a Wrapper around an existing type/struct. According to the Newtype pattern, as per Rust Book ch 19, "implementing Deref trait on the Wrapper to return an inner type would give access to all the underlying methods":
https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
Here is my implementation on a wrapper around a String. A simplified example:
struct Wrapper(String);
impl Deref for Wrapper {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.0 //pointer to Inner value
}
}
However, calling a method which consumes self throws an error:
fn main() {
let d = "Dog".to_string();
let w = Wrapper(d);
w.into_bytes();
}
Error: cannot move out of dereference of Wrapper move occurs because value has type std::string::String, which does not implement the Copy trait
Therefore I have two questions:
- What is wrong with my implementation and how do make it work?
- I'd like to make it work properly with self, &self, mut self, &mut self methods. How do I also implement DerefMut appropriately?
Solution 1:[1]
What is wrong with my implementation and how do make it work?
String::into_bytes moves the String, in your case you only have access to a reference of it &, so you cannot move it.
You could use bytes which returns an iterator to the bytes without moving it:
fn main() {
let d = "Dog".to_string();
let w = Wrapper(d);
let b = w.bytes();
println!("{b:?}");
}
I'd like to make it work properly with self, &self, mut self, &mut self methods. How do I also implement DerefMut appropriately?
You need to take into account the signatures, in general:
Deref-> Get a&TDerefMut-> Get a&mutFrom/Into-> Transform the type into an owned version of other typeT
Example using From/Into:
struct Wrapper(String);
impl From<Wrapper> for String {
fn from(w: Wrapper) -> String {
w.0
}
}
fn main() {
let d = "Dog".to_string();
let w = Wrapper(d);
let s: String = w.into();
let bytes = s.into_bytes();
println!("{bytes:?}");
}
You could also consider taking a look at the std::borrow module, which has the traits that allow you to use your types as other types.
Finally, your approach may work, but as explained before, you cannot go from &T to U in this case (you could T to U). The remaining solution is to Clone and create an owned copy:
use std::ops::Deref;
struct Wrapper(String);
impl Deref for Wrapper {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.0 //pointer to Inner value
}
}
fn main() {
let d = "Dog".to_string();
let w = Wrapper(d);
let b = w.deref().clone().into_bytes();
println!("{b:?}");
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
