新类型模式错误:无法移动取消引用的内容。

3
我想在现有类型/结构体上创建一个包装器。根据Rust Book第19章的Newtype模式,“在包装器上实现Deref特质以返回内部类型将可以访问所有底层方法”。

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 move,因为值具有类型std::string::String,它没有实现Copy特质

因此我有两个问题:

  1. 我的实现有什么问题,如何使其正常工作?
  2. 我想使用self、&self、mut self、&mut self方法使其正常工作。如何适当地实现DerefMut?

不要为 newtype 实现 DerefDeref 只应该实现于智能指针。 - Chayim Friedman
1个回答

2
我的实现有什么问题,如何使其工作? String::into_bytes 移动了String,在你的情况下,你只能访问它的引用&,所以你不能移动它。
你可以使用bytes,它返回一个字节的迭代器,而不会移动它。
fn main() {
    let d = "Dog".to_string();
    let w = Wrapper(d);
    let b = w.bytes();
    println!("{b:?}");
}

我希望能够正确使用 self、&self、mut self、&mut self 方法。如何适当地实现 DerefMut?需要考虑到方法签名,一般来说有以下几种:
- Deref -> 获取一个 &T - DerefMut -> 获取一个 &mut T - 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:?}");
}

Playground

您还可以考虑查看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:?}");
}

Playground


非常感谢您的回答。这只是一个简化的例子,实际上我甚至不是在编写String的包装器,而是另一种类型。我更关心的是通用解决方案,而不是解决方法。 - Anatoly Bugakov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接