[Программирование, Go] Вариативные функции в Go (перевод)

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
04-Сен-2020 13:31
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 использует для создания нового слайса ссылки на массив данных, лежащий в основе оригинального. Будьте внимательны, чтобы не допустить ошибку, иначе исходные данные изменятся в результате вычислений.
Удачи!
Что еще почитать:

===========
Источник:
habr.com
===========

===========
Автор оригинала: Uday Hiwarale
===========
Похожие новости: Теги для поиска: #_programmirovanie (Программирование), #_go, #_mail.ru_cloud_solutions, #_golang, #_blog_kompanii_mail.ru_group (
Блог компании Mail.ru Group
)
, #_programmirovanie (
Программирование
)
, #_go
Профиль  ЛС 
Показать сообщения:     

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

Текущее время: 22-Ноя 19:28
Часовой пояс: UTC + 5