Типы-токены
Типы с приватными конструкторами можно использовать как доказательство выполнения инвариантов.
// Copyright 2025 Google LLC
// SPDX-License-Identifier: Apache-2.0
pub mod token {
// Публичный тип с приватными полями за границей модуля.
pub struct Token { proof: () }
pub fn get_token() -> Option<Token> {
Some(Token { proof: () })
}
}
pub fn protected_work(token: token::Token) {
println!("We have a token, so we can make assumptions.")
}
fn main() {
if let Some(token) = token::get_token() {
// У нас есть токен, поэтому мы можем выполнить эту работу.
protected_work(token);
} else {
// Мы не смогли получить токен, поэтому не можем вызвать `protected_work`.
}
}
-
Мотивация: мы хотим ограничить доступ пользователя к функциональности, пока он не выполнит определённое действие.
Этого можно добиться, определив тип, который потребитель API не может создать самостоятельно, благодаря правилам приватности структур и модулей.
Newtype используют правила приватности похожим образом: они ограничивают создание значения, если только оно не гарантирует выполнение инварианта во время выполнения.
-
Спросите: зачем здесь нужно поле
proof: ()?Без
proof: ()уTokenне было бы приватных полей, и пользователи могли бы создавать значенияTokenкак угодно.Продемонстрируйте: попробуйте создать токен вручную в
mainи покажите ошибку компиляции. Продемонстрируйте: удалите полеproofизToken, чтобы показать, как пользователи могли бы создатьToken, если бы у него не было приватных полей. -
Поскольку тип
Tokenнаходится за границей модуля (token), пользователи вне этого модуля не могут создать значение самостоятельно: у них нет доступа к полюproof.Разработчик API определяет методы и функции, которые создают эти токены. Пользователь — нет.
Токен становится доказательством того, что пользователь выполнил условия доступа, установленные разработчиком API.
-
Спросите: как разработчик API может случайно создать способы обойти это ограничение?
Ожидаемые ответы: «реализации сериализации», другие парсеры и реализации «из строки», а также реализация
Default.