本当にカプセル化されているか?

newtype が公開する API サーフェス全体 を評価して、不変条件が本当に盤石かどうかを判断しなければなりません。ユーザーがバリデーションチェックを回避できてしまう可能性のある、トレイト実装を含むあらゆる相互作用を考慮することが重要です。

// 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 が強制する不変条件に違反しうる形で、基になるデータを変更するために使えてしまいます!

  • newtype の API サーフェスを監査する際は、レビュー範囲を、基になるデータへの可変アクセスを提供するメソッドやトレイトに絞り込めます。

  • 学生にプライバシー境界を思い出させてください。

    特に、newtype と同じモジュール内で定義された関数やメソッドは、その基になるデータに直接アクセスできます。可能であれば、監査の対象範囲を狭めるために、newtype の定義をそれ専用の別モジュールに移してください。