Всем привет!
TL;DR: Как отличить строку «имя» от строки «e-mail»? К примеру, чтобы не ошибиться в передаче в функцию. На помощь приходит паттерн Newtype, но его не очень удобно использовать. В статье разберем как добавить удобства.
Итак. В Rust создание обертки над типом (struct Username(String)) полезно для строгой типизации, но неудобно в использовании — приходится постоянно обращаться к полю .0. Использование трейта Deref позволяет обертке «притворяться» внутренним типом.
Зачем это нужно
Семантическая строгость: Вы не перепутаете
UsernameиEmail, хотя оба — строки. Это дает не самDeref, а само создание обертки.Прозрачный API: Вы получаете доступ ко всем методам внутреннего типа (например,
.len(),.is_empty(),.contains()) без дублирования кода.
Реализация
use std::ops::Deref;
struct Username(String);// Newtype
impl Deref for Username {
type Target = str; // Указываем целевой тип для разыменования
fn deref(&self) -> &Self::Target {
&self.0 // Возвращаем ссылку на внутренние данные
}
}
Как это работает на практике
Благодаря Deref-coercion, компилятор автоматически вызывает .deref(), когда видит, что тип не совпадает с ожидаемым, но может быть к нему приведен.
let name = Username("Anton".to_string());
// 1. Прямой вызов методов внутреннего типа &str
println!("{}", name.len());
println!("{}", name.contains("A"));
// 2. Использование в функциях, принимающих &str
fn greet(s: &str) {
println!("Hello, {s}");
}
greet(&name); // Работает автоматически
Не злоупотребляйте. Этот паттерн стоит использовать только тогда, когда ваша обертка логически является «умным указателем» или расширением внутреннего типа. Если методы внутреннего типа могут нарушить инварианты вашей структуры, лучше делегировать методы вручную.
Dhwtj
Просто напишу идиоматичный вариант
Большая часть не нужна, правда.
А вот с ускорялками
Или не писать derive AsRef , чтобы совсем инкапсуляция была
Dhwtj
Пардон, EmailError
nutype автоматически генерирует тип ошибки по имени структуры: Email => EmailError
anton_dolganin Автор
Интересное дополнение, спасибо. Но меня больше удивил подход с десериализацией e-mail. Это вы просто кусок кода взяли свой или считаете, что сразу лучше забустить тип e-mail "на будущее"?