What is the idiomatic way to convert a 1-tuple struct to the contained element?

Viewed 392

Let us say we have the following type:

struct Wrapper(Content);

Say that I often need to access the Content value of this type, destructuring it every time gets cumbersome quickly. What would be the idiomatic approach to unwrapping this value? I know of two approaches: implementing Into<Content> and implementing Deref. Maybe one of these is preferred? Or maybe there's some better-accepted way to do it?

Into approach:

impl Into<Content> for Wrapper {
    fn into(self) -> Content {
        let Wrapper(content) = self;
        content
    }
}

// ...

let content: Content = wrapper.into();

Deref approach:

impl Deref for Wrapper {
    type Target = Content;

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

// ...

let content: Content = *wrapper;
2 Answers

Deref is definitely not idiomatic. Quoting the docs:

Implementing Deref for smart pointers makes accessing the data behind them convenient, which is why they implement Deref. On the other hand, the rules regarding Deref and DerefMut were designed specifically to accommodate smart pointers. Because of this, Deref should only be implemented for smart pointers to avoid confusion.

As long as the wrapper type is not a smart pointer (this definition is in flux; there is a very long discussion in the users forum about this subject. However, usually wrapper types are not smart pointers and it's easy to judge).

Implementing Into directly is not idiomatic either. You should implement From instead. Quoting the docs again:

One should avoid implementing Into and implement From instead. Implementing From automatically provides one with an implementation of Into thanks to the blanket implementation in the standard library.

What else do we have?

  • Implementing AsRef, AsMut and From for conversions.
  • Use destructuring: let Wrapper(v) = wrapper;.
  • Directly refer the field using the dot syntax: wrapper.0.

I recommend to implement the conversion traits AsRef, AsMut and From as necessary, but use either of destructuring or dot-syntax when not working with generics. Which to use is left to your opinion - there is no strong convention in the Rust community on that.

The easiest way to access the element of a tuple or a tuple-struct is with the . syntax:

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

Note that in a tuple-struct the .0 pseudo-field is private by default, just like any other struct field. If you want to make it public, so that you do not need the impl Deref, use this syntax:

pub struct Wrapper(pub Content);

As for idiomatic, when a type can be seen as a reference to other type, is is customary to have a function as_type, as the one above. And if it can be unwrapped into that type, then into_type:

fn into_content(self) -> Content {
    self.0
}

You can also consider implementing AsRef<Content> and/or Into<Content>, but that would depend on the intented usage.

Related