3

I have:

struct Id;
struct Url;
struct IdAndUrl {
    id: Id,
    url: Url,
}

I'd like to be able to use IdAndUrl in places where I need just Id. To eliminate the noise I could use impl Deref<Id> for IdAndUrl.

Is this a good practice / idiomatic?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
dpc.pw
  • 3,462
  • 1
  • 19
  • 24

2 Answers2

6

The intention of Deref is to implement pointer types. It is supposed to convert a pointer to T to T, so dereferencing the pointer feels "natural". Using it to convert between unrelated types seems confusing.

I suggest you add a getter method id() instead.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
6

There are indeed close-to-official guidelines related with Deref and DerefMut. According to C-DEREF from the Rust API guidelines, "Only smart pointers implement Deref and DerefMut." Your suggestion to use Deref would lead to multiple issues, and so it is strongly unadvised.

Deref does not have a type parameter, but an associated type. Implementing it would have to be done as the code below, but could never be implemented for additional attributes.

// don't try this at home!
impl Deref for IdAndUrl {
    type Target = Id;

    fn deref(&self) -> &Self::Target { &self.id }
}

Moreover, a Deref implementation exposes the methods from the target type via deref coercion, polluting the struct with an interface that you might not want to have here.

One could look at the other conversion traits (namely From, AsRef, and Borrow) and see if they make sense (C-CONV-TRAITS). But from my interpretation, none of these would make sense. As already suggested in another answer, a simple getter is ideal here:

impl IdAndUrl {
    fn id(&self) -> &Id { &self.id }
}
E_net4
  • 27,810
  • 13
  • 101
  • 139