Ошибка шаблона Newtype: невозможно выйти из разыменования

Я хочу создать оболочку вокруг существующего типа/структуры. В соответствии с шаблоном 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

Поэтому у меня два вопроса:

  1. Что не так с моей реализацией и как заставить ее работать?
  2. Я хотел бы, чтобы он правильно работал с методами self, &self, mut self, &mut self. Как правильно реализовать DerefMut?

Не применяйте Deref для новых типов. Deref следует реализовывать только для интеллектуальных указателей.

Chayim Friedman 15.05.2022 03:46
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
2
1
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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 -> Получить &T
  • DerefMut -> Получить &mut
  • From/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, а другой тип. Меня больше беспокоит общее решение, а не обходной путь.

Anatoly Bugakov 13.05.2022 17:21

Другие вопросы по теме