Rust отключить построение структуры

#struct #rust #constructor #pattern-matching

#структура #Ржавчина #конструктор #сопоставление с образцом

Вопрос:

Как я могу отключить построение структуры, но сохранить соответствие шаблону в 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, ());
 
  1. Сделайте структуру неисчерпывающей
 #[non_exhaustive]
struct OrderedPair(pub u32, pub u32);
 

Проблемы заключаются в том, что с 1 я вообще не могу получить доступ к элементам, а со всеми тремя я не могу использовать сопоставление с образцом

 let OrderedPair(min, max) = my_ordered_pair;
 

Итак, есть ли способ заблокировать построение структуры, но разрешить сопоставление с образцом?

Я знаю, что если мы объявим изменяемую переменную этого типа с открытым доступом к элементам, тогда инвариант может быть нарушен путем изменения элементов вручную, но пока достаточно избегать конструктора struct .

Ответ №1:

Вместо того, чтобы выполнять сопоставление шаблонов непосредственно с полями, вы можете сделать это для возвращаемого набора:

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

Комментарии:

1. Интересно, я никогда об этом не думал. Это может быть действительно отличным компромиссом.

2. Поможет ли это, если вы реализуете функцию Deref (to pair)?

3. @hkBst Нет. Не делайте этого. Из документации : «Deref следует реализовывать только для интеллектуальных указателей, чтобы избежать путаницы» . И это очень разумный совет.

4. Это заставляет меня задуматься, является ли это интеллектуальным указателем; p… На более серьезной ноте: есть ли у вас какие-нибудь указания, как это может сбивать с толку?

5. @hkBst Вам не кажется, что будет немного непонятно, когда вы используете *x в середине цепочки итераторов и получаете не свою упорядоченную пару, а кортеж? И что происходит, когда их больше, или вам нужно применить функции, но у вас нет OrderedPair, а есть tuple ?