В чём разница между var, dynamic и явными типами в Dart?
var — выведенный статический тип (фиксируется при инициализации), явный тип — статическая аннотация для документации и безопасности, dynamic отключает статическую проверку типов и переносит ошибки в рантайм.
var, dynamic и явные типы в Dart
Dart — статически типизированный язык со звуковой системой типов. Разница между var, явным типом и dynamic фундаментальна: первые два проверяются компилятором, последний — нет.
var — выведенный статический тип
При объявлении переменной через var анализатор выводит тип из правой части присваивания. После этого тип зафиксирован и не меняется:
var name = 'Alice'; // тип: String
var count = 42; // тип: int
var ratio = 3.14; // тип: double
var items = <int>[]; // тип: List<int>
// name = 123; // ОШИБКА компиляции: int != String
name = 'Bob'; // OK
// Без инициализации — тип dynamic (не рекомендуется)
var unknown; // тип: dynamic
unknown = 'text';
unknown = 999; // OK — dynamic разрешает любое присваивание
Явные типы — документация и защита
Явная аннотация типа делает намерение очевидным, помогает IDE и защищает от случайных ошибок:
String firstName = 'Alice';
int age = 30;
List<String> tags = ['dart', 'flutter'];
Map<String, int> scores = {'math': 95, 'science': 88};
// Nullable — явно указывает, что значение может отсутствовать
String? middleName = null;
middleName = 'Marie';
// Параметры функций: всегда явные типы
String greet(String name, {int repeat = 1}) {
return List.filled(repeat, 'Hello, $name!').join(' ');
}
void main() {
print(greet('Dart', repeat: 2));
// Hello, Dart! Hello, Dart!
}
dynamic — отключение статической проверки
dynamic говорит компилятору: «не проверяй обращения к этой переменной». Все проверки перемещаются в рантайм. Это сближает Dart с динамическими языками и открывает путь к NoSuchMethodError:
dynamic value = 'hello';
print(value.length); // 5 — OK в рантайме
value = 42;
print(value.length); // RUNTIME ERROR: NoSuchMethodError
// int не имеет .length
// dynamic принимает любые вызовы без ошибки компиляции
dynamic x = getSomethingFromJson();
print(x.nonExistentMethod()); // компилируется, падает в рантайме
Object getSomethingFromJson() => 'raw data';
Object vs dynamic
Частая путаница: Object — это тоже базовый тип для всего, но он статически типизирован. Чтобы вызвать метод, нужен каст или проверка:
Object obj = 'hello';
// print(obj.length); // ОШИБКА КОМПИЛЯЦИИ — Object не имеет .length
if (obj is String) {
print(obj.length); // OK: smart cast внутри блока is
}
dynamic dyn = 'hello';
print(dyn.length); // компилируется и работает в рантайме
Когда что использовать
- Явный тип: параметры функций, поля классов, публичное API — всегда явно.
- var: локальные переменные внутри методов, когда тип очевиден из инициализатора (
var user = User()). - dynamic: обработка произвольного JSON (
Map<String, dynamic>), взаимодействие с отражением (dart:mirrors), FFI-биндинги — и больше почти нигде.
// Типичный паттерн с JSON
Map<String, dynamic> json = {
'name': 'Alice',
'age': 30,
'tags': ['dart', 'flutter'],
};
String name = json['name'] as String;
int age = json['age'] as int;
List<String> tags = List<String>.from(json['tags'] as List);
print('$name, $age, $tags');
// Alice, 30, [dart, flutter]
Подводные камни
varбез инициализатора становитсяdynamic:var x;— этоdynamic x;. Пишите явный тип или инициализируйте сразу.dynamic«заражает» выражения: результат операций сdynamicтожеdynamic, и ошибки компилятора пропадают цепочкой.- Null Safety и
dynamic:dynamicнеявно включаетnullкак допустимое значение — в отличие от non-nullable типов. Это ломает предположения об отсутствии null. - Нет автодополнения: IDE не предлагает методы для
dynamic-переменных, что замедляет разработку и скрывает опечатки. - Smart cast не работает с
dynamic: компилятор не отслеживает суженный тип послеif (x is String)дляdynamic-переменных в некоторых случаях так же надёжно, как дляObject. - Приведение типов из JSON небезопасно:
json['count'] as intброситTypeError, если сервер вернул"1"вместо1. Используйте(json['count'] as num).toInt()или явную конвертацию. - final vs var:
varподразумевает изменяемость. Предпочитайтеfinalдля переменных, которые не переприсваиваются — это явная документация намерений.
Common mistakes
- Сводить «
var,dynamicи явными типами в Dart» к синтаксису и не объяснять Future и Stream. - Игнорировать жизненный цикл, основной поток или момент освобождения ресурсов в сценарии dart-2.
- Выбирать API по привычке, не проверяя состояние, ошибки, доступность и платформенные ограничения.
What the interviewer is testing
- Формулирует точную модель для «
var,dynamicи явными типами в Dart» и подтверждает ее корректным примером. - Умеет связать ответ с isolate, тестированием и отладкой на устройстве.
- Называет ограничения подхода dart-2, включая производительность, память и сопровождение.