Rust如何禁用结构体的构造函数

3

如何在 Rust 中禁用结构体的构造但保留模式匹配呢?

让我们看一个例子:

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)
        }
    }
}

显然,我希望抑制这种结构(例如OrderedPair(2, 1))的构建,并且仅使用new方法,以保留不变性质。我知道3种实现方式:

  1. 将字段设为私有
struct OrderedPair(u32, u32);
  1. 添加一个私有的虚拟字段
struct OrderedPair(pub u32, pub u32, ());

让结构体变得不完整
#[non_exhaustive]
struct OrderedPair(pub u32, pub u32);

问题是,如果只使用1,则完全无法访问成员,而如果使用全部三个,则无法使用模式匹配。
let OrderedPair(min, max) = my_ordered_pair;

有没有一种方法可以阻止结构体构造,但允许模式匹配?

我知道,如果我们声明一个该类型的可变变量,并且对成员具有公共访问权限,则不变性可以通过手动更改成员来打破,但是现在避免结构体构造函数就足够了。

1个回答

4

你可以在返回的元组上执行模式匹配,而不是直接在字段上进行:

#[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)
    }
}

有趣,我从来没有想过。这可能是一个非常好的妥协。 - DPD-
1
你实现 Deref(到对)特质会有帮助吗? - hkBst
3
不要这样做。根据官方文档的说明,只有针对智能指针才应该实现Deref,以避免混淆。这是非常明智的建议。 - Denys Séguret
这让我考虑这是否是一个智能指针;p... 更严肃地说:你有一些指针可以解释这可能会引起的混淆吗? - hkBst
@hkBst,你不觉得在迭代器链的中间使用*x会有点不清晰吗?你将得到一个元组而不是OrderedPair。如果有更多情况发生,或者你需要应用函数但没有OrderedPair而是一个元组,那该怎么办呢? - Denys Séguret

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