DartJuniorTechnical

В чём разница между final и const в Dart?

final: ссылка присваивается один раз в рантайме, объект может быть мутабелен. const: значение известно на этапе компиляции, объект полностью иммутабелен и переиспользуется (canonicalized). В Flutter const виджеты не пересоздаются при rebuild.

final: присваивается один раз в рантайме

final переменная может быть инициализирована любым выражением, которое вычисляется в рантайме, но присваивается ровно один раз — после этого ссылку изменить нельзя. Объект, на который она ссылается, может быть мутабельным.

void main() {
  final now = DateTime.now(); // вычисляется в рантайме
  final list = [1, 2, 3];    // ссылка неизменна, но список мутабелен

  list.add(4);   // OK — меняем содержимое
  // list = [];  // Compile error — нельзя переназначить

  print(now);    // текущее время
  print(list);   // [1, 2, 3, 4]
}

const: вычисляется на этапе компиляции

const требует, чтобы значение было известно на этапе компиляции. Это compile-time constant: значение встраивается в бинарник, объект разделяется между всеми использованиями (canonicalized), и он полностью иммутабелен.

void main() {
  const pi = 3.14159;
  const greeting = 'Hello, Dart!';
  const size = Size(100, 200); // Size должен быть const-конструктором

  // const list = [DateTime.now()]; // Compile error — DateTime.now() не compile-time

  const a = [1, 2, 3];
  const b = [1, 2, 3];
  print(identical(a, b)); // true — один объект в памяти

  // a.add(4); // Unsupported operation: Cannot add to an unmodifiable list
}

Ключевые различия

finalconst
Когда вычисляетсяРантаймКомпиляция
Мутабельность объектаОбъект может быть мутабеленОбъект полностью иммутабелен
SharingКаждый раз новый объектОдин объект для одинаковых значений
Где использоватьПоля класса, локальные переменныеМагические числа, виджеты Flutter

const в Flutter — оптимизация перерисовки

Во Flutter const виджеты создаются один раз и не пересоздаются при setState. Это главная причина, почему линтер (prefer_const_constructors) агрессивно предлагает добавить const.

class MyWidget extends StatelessWidget {
  const MyWidget({super.key}); // const конструктор

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        const Text('Static label'), // пересоздаваться не будет
        Text(DateTime.now().toString()), // пересоздаётся при rebuild
        const Padding(
          padding: EdgeInsets.all(16), // EdgeInsets.all(16) — compile-time const
          child: Icon(Icons.star),
        ),
      ],
    );
  }
}

const конструктор и поля

Чтобы класс имел const конструктор, все его поля должны быть final и инициализироваться только compile-time константами.

class Point {
  final double x;
  final double y;

  const Point(this.x, this.y);

  double get distanceFromOrigin => (x * x + y * y).sqrt();
  // Оператор может быть вычислен, но не является const
}

void main() {
  const origin = Point(0, 0);
  const p1 = Point(3, 4);
  const p2 = Point(3, 4);

  print(identical(p1, p2)); // true — один объект
}

Подводные камни

  • final не защищает содержимое: final list = [] — ссылку изменить нельзя, но list.add() работает. Для иммутабельного списка нужен const или List.unmodifiable().
  • const объект нельзя изменить даже через методы: const [1,2,3].add(4) выбросит UnsupportedError в рантайме — не compile error.
  • Забытый const в Flutter: если виджет можно сделать const, но не сделали — Flutter пересоздаёт его при каждом rebuild без нужды. Линтер flutter analyze это поймает.
  • const и late несовместимы: late const — синтаксическая ошибка, потому что late по определению инициализируется в рантайме.
  • Canonicalization только для одинаковых значений: const Point(1, 2) и const Point(1, 3) — разные объекты. Sharing работает только при полном совпадении.
  • const в разных пакетах: compile-time const не переживает hot reload при изменении значения в другом пакете — нужен полный restart.

Common mistakes

  • Сводить «final и const в Dart» к синтаксису и не объяснять isolate.
  • Игнорировать жизненный цикл, основной поток или момент освобождения ресурсов в сценарии dart-3.
  • Выбирать API по привычке, не проверяя состояние, ошибки, доступность и платформенные ограничения.

What the interviewer is testing

  • Формулирует точную модель для «final и const в Dart» и подтверждает ее корректным примером.
  • Умеет связать ответ с null safety, тестированием и отладкой на устройстве.
  • Называет ограничения подхода dart-3, включая производительность, память и сопровождение.

Sources

Related topics