Добавить объявление

Как сделать правильный выбор между &self и &mut self

Выбор между &self, &mut self, self и mut self определяет поведение вашего API. Это не просто синтаксис - это контракт с пользователем. Рассмотрим на практике, как каждая форма влияет на дизайн.

Возьмем структуру Cache - кэш в памяти с TTL. Ее методы демонстрируют все формы self.

&self - наблюдатель:


impl Cache {
fn is_expired(&self, key: &str) -> bool {
// Читает данные, не изменяя кэш
}
}

Метод работает с неизменяемой ссылкой. Можно вызывать параллельно из разных потоков.

&mut self - модификатор:


impl Cache {
fn insert(&mut self, key: String, value: String) {
// Требует эксклюзивного доступа
}
}

Изменяет внутреннее состояние. Компилятор гарантирует отсутствие других ссылок в этот момент.

self - потребитель:


impl Cache {
fn into_inner(self) -> HashMap {
// Забирает владение, освобождая ресурсы
}
}

После вызова оригинальный Cache перестаёт существовать. Идеально для финализаторов.

mut self - трансформер:


impl Cache {
fn with_ttl(mut self, ttl: Duration) -> Self {
self.ttl = ttl;
self // Возвращает изменённую копию
}
}

Позволяет использовать цепочки вызовов:

Cache::new().with_ttl(...).with_capacity(...)

Вывод:


Каждая форма self устанавливает четкие правила взаимодействия с объектом. Использование &self обеспечивает безопасное чтение без побочных эффектов. Через &mut self реализуется контролируемое изменение с гарантиями исключительного доступа. Применение self знаменует передачу ответственности и завершение жизненного цикла объекта. Наконец, mut self позволяет осуществлять плавное преобразование, возвращая обновленную версию.

Осознанный выбор подходящей формы делает API не только интуитивно понятным, но и фундаментально надежным, демонстрируя, как Rust превращает строгие ограничения системы владения в ключевые преимущества для разработчика.
17.12.2025 7 220