Я хочу создать оболочку вокруг существующего типа/структуры. В соответствии с шаблоном Newtype, согласно Rust Book ch 19, «реализация типажа Deref в Wrapper для возврата внутреннего типа даст доступ ко всем базовым методам»:
https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
Вот моя реализация обертки вокруг String. Упрощенный пример:
struct Wrapper(String);
impl Deref for Wrapper {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.0 //pointer to Inner value
}
}
Однако вызов метода, который использует self, вызывает ошибку:
fn main() {
let d = "Dog".to_string();
let w = Wrapper(d);
w.into_bytes();
}
Ошибка: не может выйти из разыменования Wrapper происходит перемещение, потому что значение имеет тип std::string::String, который не реализует трейт Copy
Поэтому у меня два вопроса:

What is wrong with my implementation and how do make it work?
String::into_bytes перемещает String, в вашем случае у вас есть доступ только к ссылке на него &, поэтому вы не можете его переместить.
Вы можете использовать bytes, который возвращает итератор в байты, не перемещая его:
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?
Нужно учитывать подписи, в общем:
Deref -> Получить &TDerefMut -> Получить &mutFrom/Into -> Преобразовать тип в собственную версию другого типа TПример использования 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:?}");
}
Вы также можете взглянуть на модуль std::borrow, в котором есть свойства, позволяющие использовать ваши типы как другие типы.
Наконец, ваш подход может сработать, но, как объяснялось ранее, в этом случае вы не можете перейти от &T к U (можно от T к U). Осталось решить Clone и создать собственную копию:
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:?}");
}
Большое спасибо за ваш ответ. Это был просто упрощенный пример, на самом деле я даже не пишу обертку вокруг String, а другой тип. Меня больше беспокоит общее решение, а не обходной путь.
Не применяйте
Derefдля новых типов.Derefследует реализовывать только для интеллектуальных указателей.