Разница между dynamic, Object, var
Зачем столько вариантов?
Dart — это язык со строгой статической типизацией. Это значит, что компилятор знает тип каждой переменной ещё до запуска программы, что помогает избежать множества ошибок.
Но зачем тогда нужны var, Object и dynamic?
Они предлагают разный уровень гибкости:
var: Безопасный и удобный.Object: Безопасный, но ограниченный.dynamic: Полная свобода и полная ответственность.
var - умный вывод типов
Ключевое слово var — это не тип. Это инструкция для компилятора:
"Пожалуйста, посмотри на значение, которое я присваиваю, и сам определи тип этой переменной".
Главное правило: как только тип выведен, он фиксируется и не может быть изменён.
Dart - Использование var
// Компилятор понимает что это String
var lang = 'Dart';
// С этого момента переменная lang имеет тип String
print(lang.runtimeType); // Выведет: String
// Попытка присвоить значение другого типа вызовет ошибку компиляции.
lang = 42;
// ОШИБКА: A value of type 'int' can't be assigned to a variable of type 'String'.
Object - предок всех объектов
Object - это реальный тип данных. Это самый верхний (базовый) класс почти всех типов в Dart.
Любая переменная может быть присвоена типу Object.
Объявив переменную как Object, вы говорите компилятору:
"Я знаю, что здесь лежит какой-то объект, но я не знаю о нём ничего конкретного".
Поэтому можно вызывать только те методы, которые есть у самого класса Object
toString()hashCode()runtimeType
Dart - Использование Object
Object obj = "Dart on Flutter";
print(w.runtimeType); // Выведет: String
// Но компилятор не знает, что это строка, он видит только Object
// print(w.length); // Ошибка, нет такого свойства у Object
// Даже с проверкой на null, компилятор не даст вызвать метод.
Object? myObject = "Hello";
// print(myObject?.length); // ОШИБКА!
// Чтобы получить доступ к методам строки, нужно явно привести тип.
if (myObject is String) {
print(myObject.length); // OK, компилятор теперь уверен, что это String.
}
dynamic - отключение проверки типов
Компилятор не будет проводить никаких проверок. Вы можете вызывать любые методы и свойства у dynamic переменной. Вся ответственность за правильность вызовов ложится на вас. Проверка произойдет только в момент выполнения кода (в рантайме).
Dart - Использование dynamic
dynamic lang = 'Dart';
print(lang.length); // 4. Всё в порядке, у строки есть свойство length.
// Тип можно легко поменять. Компилятор не будет возражать.
lang = 42;
// А теперь — самое опасное. Компилятор по-прежнему нам верит.
// Он не видит здесь ошибки!
print(lang.length); // КРАШ В РАНТАЙМЕ!
// Ошибка у целого цисла не свойства length
С большой силой приходит большая ответственность. Отключив проверку типов, вы рискуете получить ошибку в работающем приложении, которую мог бы отловить компилятор.
Классический пример где может приготовится dynamic - это работа с данными в формате JSON, полученными из сети. Структура этих данных не известна на этапе компиляции.
Используйте dynamic только тогда, когда у вас нет другого выбора!
Сравнительная таблица
| Характеристика | var |
Object |
dynamic |
|---|---|---|---|
| Что это? | Ключевое слово для вывода типа | Базовый тип для всех объектов | Маркер, отключающий проверку типов |
| Проверка типов | На этапе компиляции | На этапе компиляции | На этапе выполнения (runtime) |
| Изменение типа | Нельзя после инициализации | Можно, но теряется информация о типе | Можно в любой момент |
| Доступ к методам | Доступны все методы выведенного типа | Только методы класса Object |
Доступны любые методы (без гарантий) |
| Безопасность | 🟢 Высокая | 🟡 Средняя | 🔴 Низкая |
| Основное назначение | Локальные переменные | Прием любого объекта с сохранением безопасности | Работа с нетипизированными данными (JSON) |