'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:

  1. What is wrong with my implementation and how do make it work?
  2. 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 type T

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:?}");
}

Playground

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:?}");
}

Playground

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