Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Действительно ли это инкапсулировано?

Чтобы определить, действительно ли инварианты непробиваемы, нужно оценить всю поверхность API, которую раскрывает newtype. Важно учитывать все возможные взаимодействия, включая реализации трейтов, которые могут позволить пользователям обойти проверки.

// Copyright 2025 Google LLC
// SPDX-License-Identifier: Apache-2.0

pub struct Username(String);

impl Username {
    pub fn new(username: String) -> Result<Self, InvalidUsername> {
        // Проверки...
        Ok(Self(username))
    }
}

impl std::ops::DerefMut for Username { // ‼️
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}
impl std::ops::Deref for Username {
    type Target = str;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
pub struct InvalidUsername;
  • DerefMut позволяет пользователям получить изменяемую ссылку на обёрнутое значение.

    Изменяемую ссылку можно использовать для изменения базовых данных способами, которые могут нарушить инварианты, обеспечиваемые Username::new!

  • Аудируя поверхность API newtype, можно сузить область проверки до методов и трейтов, которые предоставляют изменяемый доступ к базовым данным.

  • Напомните студентам о границах приватности.

    В частности, функции и методы, определённые в том же модуле, что и newtype, могут получить доступ к его базовым данным напрямую. Если возможно, вынесите определение newtype в отдельный модуль, чтобы сузить область аудита.