Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как сделать класс имутабельным
Имутабельность — это свойство объекта, при котором его состояние не может быть изменено после создания. Это критически важно для безопасности в многопоточной среде и предсказуемости кода.
Основные способы создания имутабельных классов
1. Использование конструктора const и финального поля
class User {
final String name;
final String email;
final int age;
const User({
required this.name,
required this.email,
required this.age,
});
}
// Использование
const user = User(
name: John,
email: john@example.com,
age: 30,
);
// ✅ Работает благодаря const
const user2 = User(
name: John,
email: john@example.com,
age: 30,
);
print(user == user2); // true, один и тот же объект в памяти
2. Аннотация @immutable
import package:flutter/foundation.dart;
@immutable
class Product {
final String id;
final String title;
final double price;
final List<String> categories;
const Product({
required this.id,
required this.title,
required this.price,
required this.categories,
});
}
Важно: @immutable — это только аннотация для анализатора, не гарантирует неизменяемость рантайме.
3. Dataclass через freezed (рекомендуется)
import package:freezed_annotation/freezed_annotation.dart;
part user.freezed.dart;
part user.g.dart;
@freezed
class User with _$User {
const factory User({
required String id,
required String name,
required String email,
}) = _User;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}
Преимущества freezed:
- Автоматическая генерация copyWith
- Equals и hashCode
- toString()
- Serialization/Deserialization
- Pattern matching в Dart 3.0+
final user = User(
id: 1,
name: John,
email: john@example.com,
);
// copyWith создаёт новый объект
final updatedUser = user.copyWith(name: Jane);
print(user == updatedUser); // false, разные объекты
4. Защита от изменения мутабельных коллекций
// ❌ Проблема: List внутри может быть изменён
@immutable
class Team {
final List<String> members;
const Team({required this.members});
}
final team = Team(members: [Alice, Bob]);
team.members.add(Charlie); // ❌ Список изменён!
// ✅ Решение 1: использовать UnmodifiableListView
import dart:collection;
@immutable
class Team {
final List<String> _members;
List<String> get members => UnmodifiableListView(_members);
const Team({required List<String> members}) : _members = members;
}
final team = Team(members: [Alice, Bob]);
team.members.add(Charlie); // Ошибка: UnsupportedError
// ✅ Решение 2: с freezed
@freezed
class Team with _$Team {
const factory Team({
required List<String> members,
}) = _Team;
}
5. Правила создания имутабельного класса
@immutable
class Point {
// ✅ Все поля final
final double x;
final double y;
// ✅ Конструктор const
const Point(this.x, this.y);
// ✅ Методы не изменяют состояние, создают новые объекты
Point translate(double dx, double dy) {
return Point(x + dx, y + dy);
}
// ✅ Переопределён equals и hashCode
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is Point &&
runtimeType == other.runtimeType &&
x == other.x &&
y == other.y;
@override
int get hashCode => x.hashCode ^ y.hashCode;
}
Практические примеры в Flutter
State Management (BLoC/Riverpod)
@freezed
class CounterState with _$CounterState {
const factory CounterState({
@Default(0) int count,
}) = _CounterState;
}
// При изменении состояния создаётся новый объект
final newState = state.copyWith(count: state.count + 1);
Сравнение объектов без equals
const user1 = User(
id: 1,
name: John,
email: john@example.com,
);
const user2 = User(
id: 1,
name: John,
email: john@example.com,
);
print(identical(user1, user2)); // true (const == кеш)
print(user1 == user2); // true
Преимущества имутабельности
✅ Безопасность в многопоточности — нет race conditions ✅ Предсказуемость — состояние не может неожиданно измениться ✅ Легче отлаживать — проще отследить изменения ✅ Оптимизация — const объекты кешируются ✅ Функциональное программирование — совместимость с реактивным стилем
Заключение
Для современного Flutter-разработчика freezed — лучший выбор. Он автоматизирует всю работу по созданию имутабельных классов и избавляет от boilerplate кода.