Привет! Представляю вашему вниманию перевод статьи про возможности пакета FIC(Fast Immutable Collections, Быстрые неизменяемые коллекции). FIC — конкурент для таких пакетов как built_collection и kt_dart, но он намного быстрее и проще в использовании.

Массивы, к которым вы, возможно, привыкли в других языках, в Dart называются списками (List), и они изменяемые по умолчанию — вы можете добавлять в них новые элементы, удалять и т.д.
var list = [1, 2]; list.add(3); // list: [1, 2, 3].
Существует способ создать неизменяемый список с помощью List.unmodifiable, список, по прежнему, будет иметь метод add, который выдаст ошибку во время исполнения, при попытке данный метод вызвать:
var list = List.unmodifiable([1, 2]); list.add(3); // Ошибка во время выполнения программы.
Однако можно делать изменения в копии такого списка:
var list = List.unmodifiable([1, 2]); // Этот список нельзя изменять. var newList = list.toList()..add(3); print(newList); // [1, 2, 3].
Есть способ лучше
Как вы поняли, обычный List можно использовать как неизменяемый, но при этом приходится писать шаблонный код, его становится трудно читать. Существует другой, более хороший способ: использование IList вместо List. IList неизменяемый — неизменяемый список, с простым API для использования.
Чтобы создать IList вы можете просто использовать extension-метод lock над обычным List:
IList<int> iList = [1, 2].lock;
Изменить содержимое IList не получится. Метод add будет возвращать новый IList с добавленным элементом:
var myList = [1, 2].lock; // Его изменить не получится. var newList = myList.add(3)); print(myList); // [1, 2]. print(newList); // [1, 2, 3].
FIC
Пакет FIC (Fast Immutable Collections, Быстрые неизменяемые коллекции) предоставляет неизменяемые списки. FIC — конкурент для таких пакетов как built_collection и kt_dart, но он намного быстрее и проще в использовании.
По ссылке Вы можете посмотреть сравнения по скорости с альтернативными пакетами. Иногда FIC даже быстрее, чем родные коллекции в Dart:

Использование
Неизменяемые коллекции имеют имена IList, ISet и IMap. Чтобы создать неизменяемую коллекцию, Вы просто можете «заблокировать» изменяемую:
IList<int> iList = [1, 2].lock; ISet<int> iSet = {1, 2}.lock; IMap<String, int> iMap = {"a": 1, "b": 2}.lock;
Любой Iterable также может быть заблокирован в неизменяемый список(List) или набор(Set) с помощью toIList() и toISet() соответственно, или используя конструкторы:
IList<int> iList = myIterable.toIList(); ISet<int> iSet = myIterable.toISet(); // С помощью конструкторов: IList<int> iList = IList(myIterable); ISet<int> iSet = ISet(myIterable);
Также можно «разблокировать» неизменяемые коллекции и получить изменяемые:
List<int> list = iList.unlock; Set<int> set = iSet.unlock; Map<String, int> map = iMap.unlock; // Работает и это: List<int> list = iList.toList(); Set<int> set = iSet.toSet(); // Работает и это: List<int> list = List.of(iList); Set<int> set = Set.of(iSet);
Но помните, что те методы, которые изменяют содержимое неизменяемых коллекций возвращают коллекции с новым содержанием. К примеру:
var iList1 = [1, 2].lock; var iList2 = iList1.add(3); // [1, 2, 3]. var iList3 = iList2.remove(2); // [1, 3]. print(iList1); // Все еще [1, 2].
Благодаря этому методы можно выстраивать в цепочку:
var iList = [1, 2, 3].lock.add(4).remove(2); // [1, 3, 4].
Равенство
По умолчанию, FIC равны, если их содержимое одинаковое и находится в одном порядке:
var iList1 = [1, 2].lock; var iList2 = [1, 2].lock; print(identical(iList1, iList2)); // false. print(iList1 == iList2); // true.
Это является полной противоположностью для обычных списков(List), которые сравниваются по идентичности:
var list1 = [1, 2]; var list2 = [1, 2]; var list3 = list1; // Обычные списки(List) сравниваются по идентичности: print(identical(list1, list2)); // false. print(identical(list1, list3)); // true. print(list1 == list2); // false. // В то время как ILists сравниваются по содержимому: print(list1.lock == list2.lock); // true.
Однако, IList является настраиваемым. Вы можете создать IList, который будет сравниваться по идентичности:
// Эти ILists сравниваются по содержимому: var iList1 = [1, 2].lock; var iList2 = [1, 2].lock; print(iList1 == iList2); // true. // Теперь эти же ILists сравниваются по идентичности: var iList3 = [1, 2].lock.withIdentityEquals; var iList4 = [1, 2].lock.withIdentityEquals; print(iList3 == iList4); // false.
Сортировка
Порядок объектов в ISet и IMap может быть и тем, который Вы изначально ввели, а может быть и отсортирован в зависимости от конфигурации:
var iSet = {2, 4, 1, 9, 3}.lock; print(iSet.join(", ")); // [2, 4, 1, 9, 3]. var iSet = {2, 4, 1, 9, 3}.lock.withConfig(ConfigSet(sort: true)); print(iSet.join(", ")); // [1, 2, 3, 4, 9].
IMapOfSets
При блокировке Map<K, V>, Вы получаете IMap<K, V>.
Однако заблокированная Map<K, Set<V>> становится IMapOfSets<K, V>:
// Map в IMap. IMap<K, V> map = {'a': 1, 'b': 2}.lock; // Map в IMapOfSets. IMapOfSets<K, V> map = {'a': {1, 2}, 'b': {3, 4}}.lock;
«Map of sets» — это вид мультисловаря(multimap). IMapOfSets позволяет добавлять и удалять объекты, не думая о наборах(sets), которые содержатся внутри.
К примеру:
IMapOfSets<K, V> map = {'a': {1, 2}, 'b': {3, 4}}.lock; print(map.add('a', 3)); // {'a': {1, 2, 3}, 'b': {3, 4}}.
По этой ссылке можно найти пример класса, называющийся StudentsPerCourse, который распределяет студентов по курсам. Каждый студент может быть записан в один или несколько курсов. Такую модель можно получить с помощью словаря(map), в котором ключами будут курсы, а значениями — наборы из студентов.
ListSet
Несмотря на свое название, FIC предлагает и изменяемые типы. К примеру, ListSet сразу же:
-
Изменяемый, упорядоченный набор(Set) фиксированного размера.
-
Изменяемый список(List) фиксированного размера, в котором значения не повторяются:
ListSet<int> listSet = ListSet.of([1, 2, 3]); expect(listSet[2], 3); expect(listSet.contains(2), isTrue); List<int> list = listSet; Set<int> set = listSet; expect(list[2], 3); expect(set.contains(2), isTrue);
Если рассматривать ListSet как Set и сравнивать с LinkedHashSet, то ListSet также является упорядоченным и имеет схожую производительность. Но ListSet занимает меньше места в памяти и может быть отсортирован, так же как и List. Также, у Вас есть доступ к его элемента по индексу за константное время.
Минусом, конечно же, является, что ListSet имеет фиксированный размер, а LinkedHashSet — нет. ListSet эффективен и как List, и как Set. Поэтому, к примеру, у него есть эффективный sort метод, в то время как LinkedHashSet требует конвертации в List, сортировки, а затем обратного преобразования в Set.
Расширения, хелперы и компараторы
FIC также предоставляет:
Iterable хелперы и расширения:
-
combineIterables— высокоуровневая функция, которая объединяет дваIterableв один. -
Iterable.isNullOrEmpty,Iterable.isNotNullOrEmptyиIterable.isEmptyButNotNull. -
Iterable.deepEqualsсравнивает два объекта по порядку с помощью оператора==. -
Iterable.deepEqualsByIdentityсравнивает все объекты по порядку с помощьюidentical. -
Iterable.findDuplicatesищет повторяющиеся значения и возвращаетSetс дубликатами. -
Iterable.removeNullsубирает все объекты, равныеnull, изIterable. -
Iterable.removeDuplicatesубирает все повторяющиеся объекты. Дополнительно, можно использоваться by функцию для сравнения объектов. Если добавить аргументremoveNullsравноеtrue, то уберутся и null-объекты. -
Iterable.sortedLikeвозвращается список, отсортированный в соответствии сIterableсортировки. Объекты, которых нет в сортировочномIterable, встанут в конец.
Расширения над List:
-
List.sortOrderedпохож на методsort, но использует сортировку слиянием(merge sort). В противовесsort,orderedSortстабильный, что означает, что различные объекты, которые сравниваются как равные, остаются в начальном порядке. -
List.sortLikeсортирует список в соответствии с orderingIterable. Объекты, которых нет в ordering, встанут в конец в определенном порядке. -
List.moveToTheFrontперемещает первое вхождение элемента в начало списка. -
List.moveToTheEndперемещает первое вхождение элемента в конец списка. -
List.whereMoveToTheFrontперемещает все элементы, которые удовлетворяют предоставленным требованиям, в начало списка. -
List.whereMoveToTheEndперемещает все элементы, которые удовлетворяют предоставленным требованиям, в конец списка. -
List.toggleЕсли элемента нет в списке, добавляет его и возвращаетtrue. Если уже есть, то удаляет первый необходимый и возвращаетfalse. -
List.compareAsSetsвозвращает true если в списке есть требуемые элементы (в любом порядке). Не берутся во внимание повторяющиеся элементы. -
List.mapIndexedпреобразует каждый элемент списка. Функция принимает изначальный элемент и его индекс. -
List.splitListубирает элементы из списка, которые удовлетворяют условию. -
List.divideListвозвращает несколько списков, разделенных по выбранным элементам. -
List.addBetweenвозвращает новый список, добавив разделение между изначальными элементами. -
List.concatвозвращает эффективное слияние до 5 списков. -
List.splitByLengthделит список на один или несколько списков с максимальным количеством элементовlength. -
List.updateвозвращает список, в котором новые элементы добавляются или обновляются в зависимости от порядкового номера. -
List.distinctудаляет повторяющиеся объекты, оставляя только уникальные. -
List.reversedViewвозвращает список объектов в обратном порядке.
Расширения над Set:
-
Set.toggleЕсли объекта нет вSet, то он добавляется и возвращаетсяtrue. Иначе, если объект уже есть вSet, то он удаляется и возвращаетсяfalse.
Расширения над Iterator:
-
toIterable,toList,toSet,toIList, иtoISetпреобразуютIteratorвIterable,List,Set,IList, иISet, соответственно.
Расширения над Boolean:
-
compareToделаетtrue > false.
Компараторы
-
compareObject -
compareObjectTo -
sortBy -
sortLike -
if0
Пакет разработан Philippe Fanaro и Marcelo Glasberg.
Другие Flutter пакеты от автора:
-
async_redux (на Medium: Асинхронный Redux: Нешаблонная версия Flutter Redux https://medium.com/flutter-community/https-medium-com-marcglasberg-async-redux-33ac5e27d5f6)
-
i18n_extension (на Medium: Потрясающе легкие переводы и интернационализация для Flutter приложений https://medium.com/flutter-community/i18n-extension-flutter-b966f4c65df9)
https://github.com/marcglasberg
https://twitter.com/GlasbergMarcelo
Читайте сообщество Flutter в Twitter: https://www.twitter.com/FlutterComm
ссылка на оригинал статьи https://habr.com/ru/company/rshb/blog/559694/
Добавить комментарий