Что такое тип dynamic в Dart и когда его стоит использовать?

Ответ

dynamic — это специальный тип в Dart, который отключает статическую проверку типов для переменной. Компилятор разрешает переменной типа dynamic содержать значение любого типа, а проверка корректности операций откладывается до времени выполнения (runtime).

Ключевые отличия:

  • dynamic vs Object: Оба могут хранить любое значение. Но с Object компилятор запрещает выполнять произвольные операции (например, вызывать методы) без явного приведения типа (as). С dynamic компилятор разрешает любые операции, а проверка произойдет в рантайме.

    Object obj = 'строка';
    // print(obj.length); // Ошибка компиляции: The getter 'length' isn't defined for 'Object'.
    print((obj as String).length); // Нужно явное приведение.
    
    dynamic dyn = 'строка';
    print(dyn.length); // Компиляция проходит, в runtime вызовется .length у String.
    dyn = 42;
    print(dyn.length); // Runtime ошибка: NoSuchMethodError (у int нет .length).
  • dynamic vs var: var — это синтаксический сахар, тип переменной выводится компилятором один раз при инициализации и далее не меняется. dynamic — это явный тип, который разрешает менять тип значения.

    var inferred = 'hello'; // Тип выведен как String.
    // inferred = 42; // Ошибка компиляции: A value of type 'int' can't be assigned.
    
    dynamic explicit = 'hello'; // Тип dynamic.
    explicit = 42; // OK.

Когда использование dynamic оправдано:

  1. Работа с JSON или внешними API со слабой типизацией: При десериализации данных неизвестной структуры, пока они не будут приведены к конкретным моделям.
    Map<String, dynamic> json = jsonDecode(response.body);
    String name = json['user']['name']; // Доступ к полям возможен, тип проверяется в runtime.
  2. Вызов методов через рефлексию (dart:mirrors) или при работе с dart:js для JavaScript-интеропа.
  3. В прототипах или скриптах, где скорость написания кода важнее его безопасности.

Рекомендация: Следует минимизировать использование dynamic в production-коде Flutter-приложений. Это ослабляет помощь инструментов (автодополнение, статический анализ) и увеличивает риск runtime-ошибок (NoSuchMethodError). Всегда предпочитайте строгую типизацию. Если структура данных известна, используйте модели с кодогенерацией (json_serializable, freezed). Если тип может быть одним из нескольких — используйте union-типы или классы-обертки.

Ответ 18+ 🔞

А, блядь, dynamic в Dart — это такой тип, который говорит компилятору: «Э, дружище, отъебись от меня со своими проверками, я сам знаю, что делаю». По факту, он просто выключает статическую проверку типов для переменной. Компилятор такой: «Ну ладно, похуй, храни что хочешь», а потом в рантайме может прилететь пиздец, если накосячил.

В чём соль, если по-простому:

  • dynamic против Object: Оба могут запихнуть в себя что угодно, но разница — просто пиздец. С Object компилятор — зануда: «Эй, я не знаю, есть ли у этой хуйни метод .length, докажи сначала, что это строка!». А с dynamic он такой: «Да хуй с тобой, делай что хочешь, но если в рантайме обосрёшься — сам дурак».

    Object obj = 'привет';
    // print(obj.length); // Не скомпилируется! Компилятор орёт: "Я нихуя не знаю про 'length' у Object!"
    print((obj as String).length); // Приходится явно говорить: "Да это же строка, ёпта!"
    
    dynamic dyn = 'привет';
    print(dyn.length); // Всё компилируется, в рантайме работает, потому что это строка.
    dyn = 42;
    print(dyn.length); // А вот тут — runtime ошибка, пиздец! У числа нет длины, ядрёна вошь!
  • dynamic против var: Тут вообще часто путают. var — это не тип, а команда компилятору: «Сам прикинь тип при инициализации и больше не меняй, умник». А dynamic — это явный тип «я-не-знаю-что-это-и-мне-похуй».

    var inferred = 'hello'; // Компилятор посмотрел и решил: "Окей, это String. Запомнил."
    // inferred = 42; // Ошибка компиляции! "Ты чё, мудила, я же сказал — это String! Нахуй int не нужен!"
    
    dynamic explicit = 'hello'; // Компилятор: "dynamic? Ну окей, твои проблемы."
    explicit = 42; // Без проблем. Сегодня строка, завтра число. Живём на грани фола.

Так когда же это ебаное dynamic реально нужно?

  1. JSON и левые API. Ну вот реально, когда с сервера приходит какая-то пиздопроебибна, и ты понятия не имеешь, что там внутри. Пока не распарсил — живёшь в анархии.
    Map<String, dynamic> json = jsonDecode(answerFromServer);
    String name = json['user']['name']; // Лезу в глубины, молясь, чтобы там была строка. Проверка — в рантайме.
  2. Рефлексия или общение с JavaScript. Это уже такие нишевые темы, где без динамики вообще нихуя.
  3. Быстрые прототипы или скрипты. Когда надо набросать идею за пять минут, а не выстраивать архитектуру как в ЦЕРНе.

Но слушай сюда, главный совет: В нормальном, продакшеновском Flutter-приложении беги от dynamic как чёрт от ладана. Это — рассадник ошибок NoSuchMethodError, которые вылезут только когда пользователь уже нажмёт на кнопку. Теряешь автодополнение, теряешь безопасность. Если структура известна — делай нормальные модели (через json_serializable). Если может быть один из нескольких типов — используй union-типы или sealed-классы. dynamic — это как отключить ABS и ESP на машине: вроде и похуй, но в один момент можешь въебаться в дерево.