Для чего нужен модификатор final в Dart?

«Для чего нужен модификатор final в Dart?» — вопрос из категории Dart Core, который задают на 44% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Модификатор final используется для объявления переменной, которая может быть инициализирована только один раз. После присвоения значения его нельзя изменить. Это обеспечивает безопасность и ясность кода, явно указывая на намерение использовать переменную как константу в рамках её области видимости.

Основные случаи использования:

  1. Константы времени выполнения: Значение вычисляется при запуске программы и затем фиксируется.
  2. Защита от изменений: Гарантирует, что ссылка на объект (или значение примитива) не будет переприсвоена.
  3. Оптимизация: Помогает компилятору в некоторых оптимизациях, хотя в меньшей степени, чем const.

Примеры:

// 1. Инициализация при объявлении
final String apiBaseUrl = 'https://api.example.com';
// apiBaseUrl = '...'; // Ошибка компиляции: 'apiBaseUrl' может быть установлена только один раз.

// 2. Инициализация в конструкторе (для полей класса)
class User {
  final String id;
  final String name;

  User(this.id, this.name); // Значения присваиваются один раз при создании объекта

  // Ошибка: final поле не может быть изменено даже внутри класса
  // void changeName(String newName) { this.name = newName; }
}

void main() {
  final user = User('u1', 'Alice');
  print(user.name); // Alice
}

// 3. Значение вычисляется во время выполнения (в отличие от const)
final DateTime appStartTime = DateTime.now(); // Корректно
// const DateTime appStartTime = DateTime.now(); // Ошибка: значение не известно во время компиляции

// 4. Final с коллекциями и объектами
final List<int> numbers = [1, 2, 3];
// numbers = [4, 5]; // Ошибка: нельзя переприсвоить ссылку
numbers.add(4); // Но можно изменять содержимое mutable-объекта! Теперь список [1, 2, 3, 4]

Важное отличие от const: const создает compile-time константу, значение которой должно быть известно уже на этапе компиляции. final — это run-time константа. Все const переменные неявно являются final, но не наоборот.

// const - известно при компиляции
const double pi = 3.14159;
const List<int> constList = [1, 2, 3]; // Список также иммутабелен

// final - может быть вычислено при выполнении
final double calculatedValue = someComplexCalculation();