Что такое Generics?

Ответ

Generics (обобщённые типы) — это механизм Dart для создания классов, функций и интерфейсов, которые могут работать с разными типами данных, сохраняя при этом безопасность типов на этапе компиляции. Они позволяют писать универсальный и переиспользуемый код.

Основная идея: Заменить конкретный тип параметром (например, T, E, K, V), который будет указан позже.

Пример универсального класса Box:

class Box<T> {
  final T contents;
  Box(this.contents);

  T getItem() => contents;
}

void main() {
  var intBox = Box<int>(42); // T заменяется на int
  var stringBox = Box<String>('Hello'); // T заменяется на String
  // stringBox.getItem() + 5; // ОШИБКА КОМПИЛЯЦИИ: String + int
}

Ограничение типов с помощью extends:

// Класс работает только с типами, являющимися подтипами num (int, double)
class NumericContainer<T extends num> {
  List<T> _values = [];
  void add(T value) => _values.add(value);
  T sum() => _values.fold(0 as T, (a, b) => (a + b) as T);
}

void main() {
  var container = NumericContainer<int>();
  container.add(10);
  container.add(20);
  print(container.sum()); // 30
  // var badContainer = NumericContainer<String>(); // Ошибка компиляции
}

Где это используется в Dart/Flutter:

  • Коллекции: List<E>, Map<K, V>, Set<E>.
  • Асинхронность: Future<T>, Stream<T>.
  • Виджеты: ValueListenableBuilder<T>, FutureBuilder<T>.
  • State Management: Provider<T>, Riverpod's Provider<T>.

Ответ 18+ 🔞

Э, слушай, вот тебе история про дженерики в Dart. Представь, что ты пишешь код, и тебе нужно, чтобы одна и та же штука работала и с числами, и со строками, и с чем угодно, но при этом чтобы компилятор не орал на тебя, как сумасшедший, когда ты попробуешь сложить строку с числом. Вот для этого они и придуманы, эти обобщённые типы, ёпта.

В чём прикол, блядь? Всё просто, как три копейки. Вместо того чтобы впиливать в класс конкретный тип вроде int, ты пишешь какую-нибудь букву — T, E, K, V. Это типа заглушка. А потом, когда создаёшь объект, говоришь: «Слушай, а вот тут вместо этой буквы T подставь-ка мне, пожалуйста, int». И всё, код становится универсальным, но при этом безопасным. Удивление пиздец, как элегантно.

Смотри, вот тебе коробка на все случаи жизни:

class Box<T> {
  final T contents;
  Box(this.contents);

  T getItem() => contents;
}

void main() {
  var intBox = Box<int>(42); // Тут T — это int, всё чётко
  var stringBox = Box<String>('Hello'); // А тут T — уже String
  // stringBox.getItem() + 5; // И вот тут компилятор тебе вмандюрит ошибку! Нельзя строку с числом мешать. Доверия ебать ноль к таким операциям.
}

Видишь? Создал коробку для чисел — клади туда только числа. Создал для строк — ну, извини, дружок, только строки. Попробуешь наебать систему — получишь по шапке на этапе компиляции. Красота.

А бывает, что нужно ограничить фантазию. Нельзя же позволять этому T быть чем угодно, а то вдруг он захочет быть, я не знаю, bool в математическом классе. Для этого есть extends.

// Этот контейнер работает ТОЛЬКО с числами (int, double). Всё остальное — на хуй.
class NumericContainer<T extends num> {
  List<T> _values = [];
  void add(T value) => _values.add(value);
  T sum() => _values.fold(0 as T, (a, b) => (a + b) as T);
}

void main() {
  var container = NumericContainer<int>();
  container.add(10);
  container.add(20);
  print(container.sum()); // 30, всё гуд
  // var badContainer = NumericContainer<String>(); // А вот это уже не прокатит. Компилятор скажет: «Чувак, ты чё, охренел? String не extends num!». И будет прав, сука.
}

Вот так, блядь, ставишь ограничение extends num и спишь спокойно. Никаких сюрпризов.

Где эта хрень валяется в Dart и Flutter? Да везде, ядрёна вошь! Смотри:

  • Коллекции: List<E>, Map<K, V>, Set<E> — это же всё дженерики, ебать копать.
  • Асинхронность: Future<T> — обещает вернуть тебе что-то типа T, Stream<T> — стримит тебе объекты типа T.
  • Виджеты во Flutter: ValueListenableBuilder<T>, FutureBuilder<T> — подстраиваются под твой тип данных.
  • State Management: Provider<T> в том же Riverpod — вообще вся суть в этом T.

Короче, без дженериков — никуда. Это как универсальная отвёртка в мире типов. Выучил принцип — и потом везде его применяешь, волнение ебать от такой мощи.

Видео-ответы