'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&T
DerefMut
-> Get a&mut
From/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 |