Rust disable struct construction

Viewed 204

How can I disable struct construction but maintaining pattern matching in Rust?

Let's see an example:

struct OrderedPair(pub u32, pub u32);

impl OrderedPair {
    fn new(a: u32, b: u32) -> Self {
        if a < b {
            Self(a, b)
        } else {
            Self(b, a)
        }
    }
}

It's obvious that I want to inhibit the construction of such struct (e.g. OrderedPair(2, 1)) and to use only the new method, in order to preserve the invariant. I know of 3 ways to do this:

  1. Make private the fields
struct OrderedPair(u32, u32);
  1. Add a private dummy field
struct OrderedPair(pub u32, pub u32, ());
  1. Make the struct non-exhaustive
#[non_exhaustive]
struct OrderedPair(pub u32, pub u32);

The issues are that with 1 I cannot access the members at all and with all three I cannot use pattern matching

let OrderedPair(min, max) = my_ordered_pair;

So is there a way to block struct construction but allow pattern matching?

I know that if we declare a mutable variable of that type with public access to members then the invariant can be broken by manually changing the members, but for now avoiding the struct constructor is enough.

1 Answers

Instead of doing pattern matching directly on the fields, you can do it on a returned tupple:

#[derive(Clone, Copy)]
pub struct OrderedPair {
    a: u32,
    b: u32,
}
impl OrderedPair {
    pub fn new(a: u32, b: u32) -> Self {
        let (a, b) = if a < b { (a, b) } else { (b, a) };
        Self { a, b }
    }
    pub fn content(self) -> (u32, u32) {
        (self.a, self.b)
    }
}
Related