Reputation: 490
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:
struct OrderedPair(u32, u32);
struct OrderedPair(pub u32, pub u32, ());
#[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.
Upvotes: 3
Views: 839
Reputation: 382112
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)
}
}
Upvotes: 4