Вариативные функции в Go

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

fade by clockbirds

Команда Mail.ru Cloud Solutions перевела статью о вариативных функциях в Go. Ее автор рассказывает, чем вариативные функции отличаются от обычных и как их создавать.

Что такое вариативная функция


Функция — фрагмент кода, предназначенный для выполнения конкретной задачи. Функции передают один или несколько аргументов, а она возвращает один или несколько результатов.

Вариативные функции — такие же, что и обычные, но они могут принимать бесчисленное или переменное число аргументов.

func f(elem ...Type)

Так выглядит типичный синтаксис вариативной функции. Оператор ..., который еще называют оператором упаковки, указывает Go сохранить все аргументы типа Type в параметре elem. Другими словами, Go создает переменную elem c типом []Type, то есть слайс. И все аргументы, передаваемые функции, сохраняются в слайсе elem.

Давайте посмотрим на примере функции append().

append([]Type, args, arg2, argsN)

Функция append ожидает, что первым аргументом будет слайс типа Type, за которым следует произвольное число аргументов. Но как добавить слайс s2 к слайсу s1?

Из определения функции append() следует, что мы не можем передать ей два слайса — аргумент типа Type только один. Поэтому мы используем оператор распаковки ..., чтобы распаковать слайс в серию аргументов. Их затем можно передать в функцию append.

append(s1, s2...)

... обозначают и оператора упаковки, и оператора распаковки. Оператор распаковки всегда стоит после имени переменной.

В нашем примере слайсы s1 и s2 одного типа. Обычно мы знаем параметры функции и количество аргументов, которые она принимает. Как же функция accept понимает, сколько параметров ей передали?

Если посмотреть на объявление функции append, то можно увидеть выражение elems ...Type. Оно упаковывает все аргументы, начиная со второго, в слайс elems.

func append(slice []Type, elems ...Type) []Type

Только последний аргумент в объявлении функции может быть вариативным.

Значит, первый аргумент функции append — только слайс, поскольку он определен как слайс. Все последующие аргументы упакованы в один аргумент под названием elems.

Теперь посмотрим, как создать собственную вариативную функцию.

Как создать вариативную функцию


Как упоминалось выше, вариативная функция — обычная функция, которая принимает переменное число аргументов. Чтобы это сделать, нужно использовать оператор упаковки ...Type.

Давайте напишем функцию getMultiples с первым аргументом factor типа int (фактор мультипликации) и переменным числом дополнительных аргументов типа int. Они будут упакованы в слайс args.

При помощи make создаем пустой слайс, он такого же размера, как и слайс args. Используя цикл for range, умножаем элементы слайса args на factor. Результат помещаем в новый пустой слайс multiples, который и вернем как результат работы функции.

func getMultiples(factor int, args ...int) []int {
	multiples := make([]int, len(args))
	for index, val := range args {
		multiples[index] = val * factor
	}
	return multiples
}

Это очень простая функция, применим ее внутри блока main().

func main() {
	s := []int{10, 20, 30}
	mult1 := getMultiples(2, s...)
	mult2 := getMultiples(3, 1, 2, 3, 4)
	fmt.Println(mult1)
	fmt.Println(mult2)
}


https://play.go.org/p/BgU6H9orhrn

Что произойдет, если в примере выше передать слайс s функции getMultiples в качестве второго аргумента? Компилятор будет сообщать об ошибке: в аргументе getMultiples он не может использовать s (type [] int) в качестве типа int. Так происходит, поскольку слайс имеет тип []int, а getMultiples ожидает параметры из int.

Как слайс передается в вариативную функцию


Слайс — ссылка на массив. Так что же происходит, когда вы передаете слайс в вариативную функцию, используя оператор распаковки? Создает ли Go новый слайс args или использует старый слайс s?

Поскольку у нас нет инструментов для сравнения, args == s, нужно изменить слайс args. Тогда узнаем, изменился ли оригинальный слайс s.


https://play.go.org/p/fbNgVGu6JZO

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

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

Удачи!

Что еще почитать:

  1. Go и кэши CPU
  2. Почему бэкенд-разработчику стоит выучить язык программирования Go
  3. Наш телеграм-канал о цифровой трансформации
Источник: https://habr.com/ru/company/mailru/blog/515428/


Интересные статьи

Интересные статьи

27 июня Яндекс проводил онлайн-хакатон по разработке навыков для Алисы. Решил и я принять в нем участие. Ранее навыки для Алисы я уже делал, но хостил их все на Google App Engine. ...
Во второй части цикла рассматривались основы языка программирования PowerShell, а сейчас стоит разобраться с использованием написанного на нем кода для задач администрирования. Самый очевидны...
Всем привет. Когда я искал информацию о журналировании (аудите событий) в Bitrix, на Хабре не было ни чего, в остальном рунете кое что было, но кто же там найдёт? Для пополнения базы знаний...
Каждый лишний элемент на сайте — это кнопка «Не купить», каждая непонятность или трудность, с которой сталкивается клиент — это крестик, закрывающий в браузере вкладку с вашим интернет-магазином.
Три года назад Марина Вязовска из Швейцарского федерального технологического института в Лозанне поразила математиков, обнаружив самый плотный способ упаковки сфер одинакового размера в восьм...