複数人への挨拶を返す
モジュールのコードへの最後の変更では、1つのリクエストで複数の人への挨拶を取得するサポートを追加します。つまり、複数値の入力を処理し、その入力の値を複数値の出力とペアにします。これを行うには、それぞれの挨拶を返すことができる関数に名前のセットを渡す必要があります。
しかし、障害があります。Hello
関数のパラメーターを単一の名前から名前のセットに変更すると、関数のシグネチャが変わります。example.com/greetings
モジュールをすでに公開しており、ユーザーがすでにHello
を呼び出すコードを作成している場合、その変更はプログラムを壊してしまいます。
このような状況では、別の名前で新しい関数を作成する方が良い選択です。新しい関数は複数のパラメーターを受け取ります。これにより、旧関数は下位互換性のために維持されます。
- greetings/greetings.goで、コードが次のようになるように変更します。
package greetings import ( "errors" "fmt" "math/rand" ) // Hello returns a greeting for the named person. func Hello(name string) (string, error) { // If no name was given, return an error with a message. if name == "" { return name, errors.New("empty name") } // Create a message using a random format. message := fmt.Sprintf(randomFormat(), name) return message, nil } // Hellos returns a map that associates each of the named people // with a greeting message. func Hellos(names []string) (map[string]string, error) { // A map to associate names with messages. messages := make(map[string]string) // Loop through the received slice of names, calling // the Hello function to get a message for each name. for _, name := range names { message, err := Hello(name) if err != nil { return nil, err } // In the map, associate the retrieved message with // the name. messages[name] = message } return messages, nil } // randomFormat returns one of a set of greeting messages. The returned // message is selected at random. func randomFormat() string { // A slice of message formats. formats := []string{ "Hi, %v. Welcome!", "Great to see you, %v!", "Hail, %v! Well met!", } // Return one of the message formats selected at random. return formats[rand.Intn(len(formats))] }
このコードでは、
- パラメーターが単一の名前ではなく名前のスライスである
Hellos
関数を追加します。また、戻り値の型をstring
からmap
に変更して、名前を挨拶メッセージにマッピングして返すことができるようにします。 - 新しい
Hellos
関数に既存のHello
関数を呼び出させます。これにより、両方の関数をそのまま残しながら、重複を減らすことができます。 - 受信した各名前(キーとして)を生成されたメッセージ(値として)に関連付ける
messages
マップを作成します。Goでは、マップは次の構文で初期化します:make(map[キーの型]値の型)
。Hellos
関数はこのマップを呼び出し元に返します。マップの詳細については、GoブログのGoのマップの動作を参照してください。 - 関数が受信した名前をループ処理し、それぞれが空でない値を持っていることを確認し、その後、各名前をメッセージと関連付けます。この
for
ループでは、range
は2つの値を返します。ループ内の現在のアイテムのインデックスとアイテムの値のコピーです。インデックスは不要なため、Goの空白識別子(アンダースコア)を使用して無視します。詳細については、Effective Goの空白識別子を参照してください。
- パラメーターが単一の名前ではなく名前のスライスである
- hello/hello.goの呼び出しコードで、名前のスライスを渡し、返された名前/メッセージのマップの内容を出力します。
hello.goで、コードが次のようになるように変更します。
package main import ( "fmt" "log" "example.com/greetings" ) func main() { // Set properties of the predefined Logger, including // the log entry prefix and a flag to disable printing // the time, source file, and line number. log.SetPrefix("greetings: ") log.SetFlags(0) // A slice of names. names := []string{"Gladys", "Samantha", "Darrin"} // Request greeting messages for the names. messages, err := greetings.Hellos(names) if err != nil { log.Fatal(err) } // If no error was returned, print the returned map of // messages to the console. fmt.Println(messages) }
これらの変更により、
- 3つの名前を保持するスライス型として
names
変数を作成します。 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機能を使用して、コードのユニットテストを作成します。