将一个1元组结构体转换为包含的元素的惯用方法是什么?

3

假设我们有以下类型:

struct Wrapper(Content);

我通常需要访问此类型的Content值,每次解构都很麻烦。那么,展开此值的惯用方法是什么?我知道两种方法:实现Into<Content>和实现Deref。也许其中一种更可取?或者可能有更好的方式来完成吗?
impl Into<Content> for Wrapper {
    fn into(self) -> Content {
        let Wrapper(content) = self;
        content
    }
}

// ...

let content: Content = wrapper.into();

Deref方法:

impl Deref for Wrapper {
    type Target = Content;

    fn deref(&self) -> &Self::Target {
        let Wrapper(content) = self;
        content
    }
}

// ...

let content: Content = *wrapper;

4
我通常会写&self.0,你考虑过这点了吗?还是你在谈论如何从Wrapper实现的外部使用这个类型? - rodrigo
https://doc.rust-lang.org/std/primitive.tuple.html - Denys Séguret
啊,我一直在尝试&self[0],但是出现了错误。无论如何,尽可能地让包装类型像内容类型一样被处理。所以,是的,我想经常在包装器外使用它。 - Miguel Bartelsman
@rodrigo 如果您认为这是合适的方法,能否将其发布为答案? - Miguel Bartelsman
滥用 Deref 时要小心。您不总能理解代码中发生的事情。 - Denys Séguret
2个回答

8

Deref 明显不是惯用语。引用 文档

为智能指针实现 Deref 使得方便地访问它们背后的数据成为可能,这也是它们实现 Deref 的原因。另一方面,关于 DerefDerefMut 的规则是专门设计用来适应智能指针的。因此,只有智能指针才应该实现 Deref,以避免混淆。

只要包装类型不是智能指针(这个定义正在变化;用户论坛上有一个非常长的讨论关于这个主题。但通常包装类型不是智能指针,很容易判断)。

直接实现 Into 也不符合惯用法。您应该实现 From。再次引用 文档

应避免实现 Into,而是应该实现 From。由于标准库中的默认实现,实现 From 自动提供了 Into 的实现。

还有什么别的吗?
  • 实现转换的 AsRefAsMutFrom
  • 使用解构: let Wrapper(v) = wrapper;
  • 直接使用点语法引用字段: wrapper.0

我建议根据需要实现转换特性AsRefAsMutFrom,但在不使用泛型时请使用解构或点语法之一。使用哪种方法取决于您的意见-在Rust社区中没有强烈的惯例。


4

访问元组或元组结构体中的元素,最简单的方法是使用. 语法:

impl Wrapper {
    fn as_content(&self) -> &Content {
        &self.0
    }
}

请注意,元组结构体中的.0伪字段默认是私有的,就像其他任何结构体字段一样。如果您想将其公开,以便无需impl Deref,请使用以下语法:
pub struct Wrapper(pub Content);

关于 "惯用的",当一个类型可以被视为对其他类型的引用时,通常会有一个名为 as_type 的函数,就像上面那个例子一样。如果它可以被解包成该类型,则使用 into_type:
fn into_content(self) -> Content {
    self.0
}

您也可以考虑实现AsRef<Content>和/或Into<Content>, 但这取决于预期的使用方式。


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