Возврат приветствий для нескольких людей
В последних изменениях, которые вы внесёте в код вашего модуля, вы добавите поддержку получения приветствий для нескольких людей в одном запросе. Другими словами, вы будете обрабатывать многозначный входной параметр, а затем сопоставлять значения этого параметра с многозначным выходным результатом. Для этого вам нужно будет передать набор имён в функцию, которая может вернуть приветствие для каждого из них.
Но есть одна особенность. Изменение параметра функции Hello с одного имени на набор имён изменит сигнатуру функции. Если вы уже опубликовали модуль example.com/greetings, а пользователи уже написали код, вызывающий Hello, то это изменение сломает их программы.
В такой ситуации лучше создать новую функцию с другим именем. Новая функция будет принимать несколько параметров. Это сохранит старую функцию для обратной совместимости.
-
В файле greetings/greetings.go измените код так, чтобы он выглядел следующим образом.
package greetings import ( "errors" "fmt" "math/rand" ) // Hello возвращает приветствие для указанного человека. func Hello(name string) (string, error) { // Если имя не было указано, возвращает ошибку с сообщением. if name == "" { return name, errors.New("empty name") } // Создаёт сообщение, используя случайный формат. message := fmt.Sprintf(randomFormat(), name) return message, nil } <ins>// Hellos возвращает карту, которая сопоставляет каждому из указанных людей // сообщение приветствия. func Hellos(names []string) (map[string]string, error) { // Карта для сопоставления имён с сообщениями. messages := make(map[string]string) // Проходит по полученному срезу имён, вызывая // функцию Hello, чтобы получить сообщение для каждого имени. for _, name := range names { message, err := Hello(name) if err != nil { return nil, err } // В карте сопоставляет полученные сообщения с // именами. messages[name] = message } return messages, nil }</ins> // randomFormat возвращает одно из нескольких сообщений приветствия. Возвращаемое // сообщение выбирается случайным образом. func randomFormat() string { // Срез форматов сообщений. formats := []string{ "Hi, %v. Welcome!", "Great to see you, %v!", "Hail, %v! Well met!", } // Возвращает один из форматов сообщений, выбранный случайным образом. return formats[rand.Intn(len(formats))] }В этом коде вы:
-
Добавляете функцию
Hellos, параметром которой является срез имён, а не одно имя. Также вы изменяете один из типов возвращаемых значений сstringнаmap, чтобы можно было возвращать сопоставление имён с сообщениями приветствия. -
Заставляете новую функцию
Hellosвызывать существующую функциюHello. Это помогает уменьшить дублирование кода, при этом оставляя обе функции на месте. -
Создаёте карту
messagesдля сопоставления каждого полученного имени (в качестве ключа) с сгенерированным сообщением (в качестве значения). В Go инициализация карты происходит следующим образом:make(map[key-type]value-type). ФункцияHellosвозвращает эту карту вызывающей стороне. Более подробно о картах можно прочитать в статье Go maps in action в блоге Go. -
Проходит по всем полученным именам, проверяет, что каждое из них не пустое, а затем сопоставляет с сообщением. В этом цикле
forrangeвозвращает два значения: индекс текущего элемента в цикле и копию значения элемента. Вам не нужен индекс, поэтому вы используете пустой идентификатор Go (подчёркивание) для его игнорирования. Более подробно см. The blank identifier в Effective Go.
-
Добавляете функцию
-
В коде вызова в hello/hello.go передайте срез имён, а затем распечатайте содержимое карты имён/сообщений, которую вы получите.
В hello.go измените код так, чтобы он выглядел следующим образом.
package main import ( "fmt" "log" "example.com/greetings" ) func main() { // Устанавливает свойства предопределённого Logger, включая // префикс записи журнала и флаг, чтобы отключить вывод // времени, файла и номера строки. log.SetPrefix("greetings: ") log.SetFlags(0) <ins>// Срез имён. names := []string{"Gladys", "Samantha", "Darrin"} // Запрашивает сообщения приветствия для имён. messages, err := greetings.Hellos(names)</ins> if err != nil { log.Fatal(err) } <ins>// Если ошибок не было, распечатывает возвращённую карту // сообщений в консоль. fmt.Println(messages)</ins> }С этими изменениями вы:
-
Создаёте переменную
namesкак тип среза, содержащий три имени. -
Передаёте переменную
namesв качестве аргумента функцииHellos.
-
Создаёте переменную
-
В командной строке перейдите в каталог, содержащий hello/hello.go, а затем используйте
go run, чтобы подтвердить, что код работает.Вывод должен быть строковым представлением карты, сопоставляющей имена с сообщениями, примерно следующим:
$ go run . map[Darrin:Hail, Darrin! Well met! Gladys:Hi, Gladys. Welcome! Samantha:Hail, Samantha! Well met!]
В этой теме были представлены карты для представления пар имя/значение. Также была рассмотрена идея сохранения обратной совместимости путём реализации новой функции для новой или изменённой функциональности в модуле. Более подробно о совместимости модулей можно прочитать в статье Keeping your modules compatible.
Далее вы будете использовать встроенные функции Go для создания модульного теста для своего кода.