Оценок пока нет Обобщения — Generics в языке Dart

Если вы посмотрите на документацию API для базового типа массива List, вы увидите, что тип на самом деле List<E>. Нотация <…> помечает List как универсальный (или параметризованный) тип — тип, имеющий параметры формального типа. По соглашению, большинство переменных типа имеют однобуквенные имена, такие как E, T, S, K и V.

Зачем использовать дженерики?

Обобщения часто требуются для обеспечения безопасности типов, но они имеют больше преимуществ, чем просто запуск кода:

  • Правильное указание универсальных типов приводит к лучшему сгенерированному коду.
  • Вы можете использовать дженерики для уменьшения дублирования кода.

Если вы хотите, чтобы список содержал только строки, вы можете объявить его как List<String> (читается как «список строк»). Таким образом, вы, ваши коллеги-программисты и ваши инструменты можете обнаружить, что присвоение нестрокового списка, вероятно, является ошибкой. Вот пример:

var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
names.add(42); // Error

Еще одна причина использования обобщений заключается в уменьшении дублирования кода. Обобщения позволяют вам совместно использовать единый интерфейс и реализацию для многих типов, в то же время используя преимущества статического анализа. Например, допустим, вы создали интерфейс для кэширования объекта:

abstract class ObjectCache {
  Object getByKey(String key);
  void setByKey(String key, Object value);
}

Вы обнаружите, что вам нужна специфичная для строки версия этого интерфейса, поэтому вы создаете другой интерфейс:

abstract class StringCache {
  String getByKey(String key);
  void setByKey(String key, String value);
}

Позже вы решите, что вам нужна специфичная для номера версия этого интерфейса … Вы поняли идею.

Универсальные типы могут избавить вас от необходимости создавать все эти интерфейсы. Вместо этого вы можете создать один интерфейс, который принимает параметр типа:

abstract class Cache<T> {
  T getByKey(String key);
  void setByKey(String key, T value);
}

В этом коде T является типом stand-in. Это заполнитель, который вы можете рассматривать как тип, который разработчик определит позже.

Использование литералов коллекции

Список, набор и литералы карты могут быть параметризованы. Параметризованные литералы аналогичны литералам, которые вы уже видели, за исключением того, что вы добавляете <type> (для списков и наборов) или <keyTypevalueType> (для карт) перед открывающей скобкой. Вот пример использования типизированных литералов:

var names = <String>['Seth', 'Kathy', 'Lars'];
var uniqueNames = <String>{'Seth', 'Kathy', 'Lars'};
var pages = <String, String>{
  'index.html': 'Homepage',
  'robots.txt': 'Hints for web robots',
  'humans.txt': 'We are people, not machines'
};

Использование параметризованных типов с конструкторами

Чтобы указать один или несколько типов при использовании конструктора, поместите типы в угловые скобки (<...>) сразу после имени класса. Например:

var nameSet = Set<String>.from(names);

Следующий код создает карту с целочисленными ключами и значениями типа View:

var views = Map<int, View>();

Коллекции обобщений и типы, которые они содержат

Универсальные типы Dart являются реализованными, что означает, что они переносят информацию своего типа во время выполнения. Например, вы можете проверить тип коллекции:

var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List<String>); // true
Примечание. В отличие от универсальных в Java используется стирание, что означает, что параметры универсального типа удаляются во время выполнения. В Java вы можете проверить, является ли объект списком, но вы не можете проверить, является ли он списком List<String>.

Ограничение параметризованного типа

При реализации универсального типа вы можете захотеть ограничить типы его параметров. Вы можете сделать это, используя extends.

class Foo<t extends="" somebaseclass=""> {
  // Implementation goes here...
  String toString() => "Instance of 'Foo<$T>'";
}

class Extender extends SomeBaseClass {...}

Можно использовать SomeBaseClass или любой из его подклассов в качестве универсального аргумента:

var someBaseClassFoo = Foo<SomeBaseClass>();
var extenderFoo = Foo<extender>();

Также можно указать общий аргумент:

var foo = Foo();
print(foo); // Instance of 'Foo<SomeBaseClass>'

Указание любого типа, отличного от SomeBaseClass, приводит к ошибке:

var foo = Foo<Object>();

Использование методов обобщений

Первоначально общая поддержка Dart была ограничена классами. Более новый синтаксис, называемый обобщенными методами, допускает аргументы типа для методов и функций:

T first<T>(List<T> ts) {
  // Do some initial work or error checking, then...
  T tmp = ts[0];
  // Do some additional checking or processing...
  return tmp;
}

Здесь параметр общего типа для first(<T>) позволяет вам использовать аргумент типа T в нескольких местах:

  • В возвращаемом типе функции (T).
  • В типе аргумента (List<T>).
  • В типе локальной переменной (T tmp).

Для получения дополнительной информации о дженериках см. Использование универсальных методов.

Пожалуйста, оцените материал

WebSofter

Web - технологии