Давайте создадим функцию карты, которая вызывает обратный вызов для каждого элемента в массиве/срезе.

Сегодня мы собираемся создать функцию, которая вызывает обратный вызов для каждого элемента нашего массива/среза, чтобы настроить соответствующее значение и вернуть его. Теперь вы можете спросить себя: «Какого черта! Зачем мне это делать?». Что ж, представьте, если бы вам пришлось писать каждое слово в массиве с большой буквы, инвертировать логические значения или умножать каждое число на другое.

Есть много ситуаций, подобных этой, когда такая функция может быть полезна. К сожалению, в Go вам придется разрабатывать такую ​​функцию карты самостоятельно. Но не волнуйтесь. Сегодня мы рассмотрим, как реализовать такую ​​функцию самостоятельно. Так что пристегнитесь, и давайте начнем.

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

вступление

Одна вещь, прежде чем мы начнем. Для нашего решения нам нужны дженерики. Это означает, что мы должны снова использовать Golang версии 1.18.

Подход

То, что мы хотим, довольно просто и может быть разбито на три шага:

  1. Мы хотим вызвать обратный вызов с каждым элементом в массиве/срезе.
  2. Скорректированные значения должны быть сохранены в новом срезе.
  3. В конце функция должна вернуть скорректированные значения.

Решение

Для этого наша функция должна принимать два аргумента. Первый — это наш массив, а второй — обратный вызов. Ниже вы можете увидеть нашу основную функцию Map. Мы перебираем наш массив, вызываем наш обратный вызов для каждого элемента и добавляем скорректированные значения в наш новый срез. В конце концов, все, что нам нужно сделать, это вернуть наш новый фрагмент.

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

Улучшения

В прошлый раз мы использовали «сопоставимый» универсальный тип. На этот раз нам нужен общий тип «любой». Как вы можете видеть ниже, нам нужно написать наше универсальное имя T в скобках сразу после имени функции и присвоить ему тип «любой». Мы также присваиваем двум параметрам тип T, а также временный срез результата. Это позволяет нам указать, какой массив ожидает наша функция и какого типа должен быть результирующий срез.

Чтобы использовать его, мы должны сделать следующий вызов функции:
Map[int]([1, 2], func(num int){return num + 1}) .
Слово «int» в скобках указывает наш универсальный тип.

Ориентир

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

go test -bench="BenchmarkMap" -run=^# -benchtime=10000x

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

Заключение

Я надеюсь, что метод вызова обратного вызова для каждого элемента массива был интересным и полезным. Если у вас есть другое решение, что-то упомянуть или вопросы, было бы здорово, если бы вы оставили их в комментариях. До скорой встречи.

P.S. Это третья статья из новой запланированной мною серии. В течение следующих нескольких недель я рассмотрю различные общие вспомогательные функции, интересные тесты и полезные функции.

Если вы так же взволнованы, как и я, следите за обновлениями!