Преимущества использования Lodash на языке Go без раздумий

1656577933 preimushhestva ispolzovaniya lodash na yazyke go bez razdumij

автором Tal Kol

T7io7sSXVIifWU1Iaugs8ti6OaQu-ukfiBSB

Работая с Node.js, я стал полагаться на Lodash как бесценный инструмент. Он дополняет стандартную библиотеку JavaScript набором удобных функциональных операторов над коллекциями. Я не могу вспомнить ни один проект JavaScript, над которым я работал в течение последних лет, и не использовал его.

Мой опыт перехода на Go был очень приятным. Go решает много проблем, которые у меня с Node.js на протяжении многих лет, и все же производительный. Но мне очень не хватало одной вещи – библиотеки, как Lodash.

Что такого замечательного в Лодаше?

JavaScript не является чисто функциональным языком, и большинство кода, который я пишу на JavaScript, как правило, является обязательным. Тем не менее некоторые принципы функционального программирования (например, операторы цепи и неизменность) очень полезны при работе с коллекциями.

Скажем, у меня есть массив с некоторыми дубликатами, которые хочу удалить. Все, что нужно, это одна строчка из Lodash:

Скажем, я хочу сохранить только цвета, названия которых длиннее 4 букв. Это также занимает одну строчку:

А теперь допустим, что я хочу написать первую букву каждого цвета с большой… да, не больше одной строчки. Я даже могу сделать все вышеперечисленное вместе:

Lodash, пожалуй, самый удобный инструмент для работы с коллекциями в JavaScript.

Как бы вы это сделали в Go?

Начнём с первой задачи: получить уникальный срез. Поиск в Google наилучшего решения Go дает эту публикацию в блоге как первый результат. Вот код, кредиты Кайлу Бэнксу:

Вы можете себе представить, что если бы нам пришлось также фильтровать и использовать первую букву каждого цвета, мы бы потратили слишком много времени на механику этих действий. Это было бы немного утомительно. Где мои единственные лайнеры?

Библиотеки в помощь

Конечно, есть некоторые библиотеки, выполняющие эти удобные действия для нас. Удивительно, но у Go не так много популярных. Почему так?

Чтобы сделать такую ​​библиотеку полезна, она должна поддерживать многие типы коллекций. Это потому, что у вас может быть фрагмент строк, фрагмент целых чисел или фрагмент структур. Поддерживая а общий Тип фрагмента не прост в Go.

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

Итак, как мы можем реализовать такую ​​библиотеку без генериков? Гуру Go Роб Пайк показывает пример реализации функции filter в этом репозитории Github. Обратите внимание на интенсивное использование отображения. Действительно, расширить эту технику и реализовать разные методы утилиты Lodash нетрудно. Вы можете увидеть пример проекта, пытающегося сделать именно это здесь.

Почему нам лучше избегать размышлений?

Reflection исследует типы при выполнении. Устраняя отсутствие у Go генериков с отображением, мы переносим тяжелую работу с несколькими типами коллекций от времени компиляции до времени исполнения.

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

Итак, как мысленный эксперимент, что мы можем сделать вместо этого? Можем ли мы создать по-настоящему эффективную реализацию Lodash в Go, которая будет конкурировать со старинным цикл for подход с точки зрения производительности?

Скомпилировать генерацию временного кода

Генерация кода как части цепи инструментов разработки не является чужой концепцией в Go. Он используется компилятором Protobuf для создания методов доступа Go к определениям протоколов. Он даже был представлен как официальная функция Go toolchain go generate из версии 1.4.

Что если мы хотим перенести тяжелую работу с общими типами коллекций обратно на время компиляции? Лучший способ сделать это (сейчас) – создать специфический для типа код для каждого из типов, которые нам нужны в нашем проекте!

Рассмотрим реализацию от до uniq над а string ломтик:

Чем будет отличаться реализация, если нам нужна поддержка для int ломтик?

Как вы видите, это почти одинаково, за исключением каждого случая string было заменено на int.

Можем ли мы как-нибудь сделать это автоматически?

Лодаш в Go без раздумий

Давайте сначала разработаем наш API. Мы можем обратиться за вдохновением к оригинальной реализации Lodash в JavaScript. Здесь библиотека используется с символом подчеркивания _. Например, _.uniq().

Мы можем воздать честь, соблюдая ту же конвенцию. Разница состоит в том, что в нашем случае за символом подчеркивания следует тип. Например, _int.Uniq() для целых чисел и _string.Uniq() для струн. Мы должны четко указать тип, поскольку мы собираемся получить совершенно новую и специальную реализацию всей библиотеки для конкретного типа, который нам нужен. Это гарантирует, что наше время выполнения будет максимально эффективным.

Использование очень простое. Просто импортируйте нужную реализацию:

Есть десятки возможных типов. Значит ли это, что наша go-dash/slice библиотека должна прийти с каждым? Не очень, поскольку это было бы непрактично. Мы собираемся генерировать необходимые реализации динамически во время компиляции!

Чтобы добиться этого, мы представим интересный инструмент командной строки: _genгенератор кода для реализации нашей библиотеки Lodash (обратите внимание, как он также начинается с подчеркивания).

Когда _gen запускается в корневом коде любого проекта, он просматривает все исходные файлы в проекте и ищет github.com/go-dash/slice/_TYPE импорта. В приведенном выше примере он найдет один для _string и один для _int. Затем генератор динамически сгенерирует реализацию для этих конкретных типов и добавит ее в библиотеку, найденную в рабочей области Go под путем$GOPATH/src/github.com/go-dash/slice.

Реализация go-dash/slice на Github действительно очень худой. Он содержит только шаблонную реализацию одного общего типа. Генератор кода полагается на этот шаблон для создания конкретных реализаций типа в соответствии с вашими требованиями при компиляции проекта.

А как насчет пользовательских типов?

Предположим, что ваш проект определяет пользовательский сложный тип, например Person:

Было бы достаточно удобно, если бы мы могли использовать нашу библиотеку Lodash на a Person также порезать. Ну, на самом деле это может работать точно так же. Просто импортируйте реализацию go-dash/slice что работает на Person а генератор кода позаботится о другом:

Рабочий прототип

Концепция рабочего доказательства go-dash/slice библиотека, которая предоставляет несколько полезных функций, например uniq, filter и chainдоступно на Github.

В проекте также есть рабочий генератор командной строки.

Генератор командной строки удобно установить на Mac через Homebrew: brew install go-dash/tools/gen

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

Если вам нравится это направление и вы хотите помочь перенести остальные полезные функции Lodash в Go, пожалуйста, внесите свой вклад.

Несколько последних мыслей о синтаксисе

Главное, что все еще беспокоит меня с избранным синтаксисом, это то, что у нас есть импорт для каждого типа. Можно ли объединить их в одну реализацию, которая будет направлять в правильное место по типу?

Учитывайте следующее:

Этот код объединяет все реализации в унифицированный Uniq что занимает interface{}. Хотя он не использует отображение как таковое, он все еще имеет два динамических преобразования при выполнении и переключатель, который повлияет на производительность. Нам, вероятно, следует провести сравнительный анализ, чтобы увидеть, насколько это оказывает влияние. Нам также, вероятно, следует сравнить реализацию отражения и проверить, действительно ли наши подозрения в производительности во время выполнения были обоснованными.

Тем не менее, это был веселый мыслительный эксперимент.

Тал является основателем Orbs.com – общедоступной инфраструктуры блокчейн для крупномасштабных потребительских приложений с миллионами пользователей. Чтобы узнать больше и ознакомиться с белыми документами Orbs, нажмите здесь. [Follow on Telegram, Twitter, Reddit]

Примечание: если вас интересует блокчейн – приходите! Orbs – это проект с полностью открытым кодом, в котором может принять участие любой.

JWn9bUEABxzB3UAy7kCsYdYnHPsCsH8cDevu

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *