суббота, 10 апреля 2021 г.

Создание модуля в Golang: ответные приветствия для нескольких человек

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

Примечание. Этот раздел является частью руководства, состоящего из нескольких частей, которое начинается с создания модуля Go.

Но есть загвоздка. Изменение параметра функции Hello с одного имени на набор имен приведет к изменению сигнатуры функции. Если вы уже опубликовали модуль example.com/greetings, а пользователи уже написали код, вызывающий Hello, это изменение нарушит их программы.

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

1. В greetings/greetings.go измените свой код так, чтобы он выглядел следующим образом.

package greetings

import (
    "errors"
    "fmt"
    "math/rand"
    "time"
)

// Hello возвращает приветствие для указанного человека.
func Hello(name string) (string, error) {
    // Если имя не было указано, возвращаем ошибку с сообщением.
    if name == "" {
        return name, errors.New("empty name")
    }
    // Создаем сообщение в произвольном формате.
    message := fmt.Sprintf(randomFormat(), name)
    return message, nil
}

// 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
}

// Init устанавливает начальные значения для переменных, 
// используемых в функции.
func init() {
    rand.Seed(time.Now().UnixNano())
}

// 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, параметр которой представляет собой срез имен, а не одно имя. Кроме того, вы меняете один из возвращаемых им типов со строки на карту, чтобы вы могли возвращать имена, сопоставленные с приветственными сообщениями.
  • Пусть новая функция Hellos вызовет существующую функцию Hello. Это помогает уменьшить дублирование, оставив при этом обе функции на своих местах.
  • Создаете карту сообщений, чтобы связать каждое из полученных имен (как ключ) со сгенерированным сообщением (как значение). В Go вы инициализируете карту со следующим синтаксисом: make(map[key-type]value-type). У вас есть функция Hellos, возвращающая эту карту вызывающей стороне.
  • Пройдете в цикле по именам, полученным вашей функцией, проверяя, что каждое из них имеет непустое значение, затем свяжете с каждым сообщение. В этом цикле for range возвращает два значения: индекс текущего элемента в цикле и копию значения элемента. Вам не нужен индекс, поэтому вы используете пустой идентификатор Go (подчеркивание), чтобы игнорировать его.

2. В коде вызова hello/hello.go передайте срез имен, а затем распечатайте содержимое карты имен/сообщений, которую вы получите.

В hello.go измените свой код так, чтобы он выглядел следующим образом.

package main

import (
    "fmt"
    "log"

    "example.com/greetings"
)

func main() {
    // Устанавливаем свойства предопределенного Logger,
    // включая префикс записи журнала и флаг отключения печати
    // времени, исходного файла и номера строки.
    log.SetPrefix("greetings: ")
    log.SetFlags(0)

    // Срез имен.
    names := []string{"Gladys", "Samantha", "Darrin"}

    // Запрашиваем приветственные сообщения для имен.
    messages, err := greetings.Hellos(names)
    if err != nil {
        log.Fatal(err)
    }
    // Если ошибок не было, распечатываем возвращенную карту
    // сообщения на консоль.
    fmt.Println(messages)
}

С этими изменениями вы:

  • Создаете переменную имен как тип среза, содержащий три имени.
  • Передаете переменную names в качестве аргумента функции Hellos.

3. В командной строке перейдите в каталог, содержащий hello/hello.go, затем используйте команду go run, чтобы убедиться, что код работает.

Вывод должен быть строковым представлением карты, связывающей имена с сообщениями, примерно следующего вида:

$ go run .
map[Darrin:Hail, Darrin! Well met! Gladys:Hi, Gladys. Welcome! Samantha:Hail, Samantha! Well met!]

В этом посте представлены карты для представления пар имя/значение. Он также представил идею сохранения обратной совместимости путем реализации новой функции для новых или измененных функций в модуле.

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


Читайте также:


Комментариев нет:

Отправить комментарий