| <!--{ | |
| "Title": "Return greetings for multiple people", | |
| "Breadcrumb": true | |
| }--> | |
| <p> | |
| In the last changes you'll make to your module's code, you'll add support for | |
| getting greetings for multiple people in one request. In other words, you'll | |
| handle a multiple-value input, then pair values in that input with a | |
| multiple-value output. To do this, you'll need to pass a set of names to a | |
| function that can return a greeting for each of them. | |
| </p> | |
| <aside class="Note"> | |
| <strong>Note:</strong> This topic is part of a multi-part tutorial that begins | |
| with <a href="/doc/tutorial/create-module.html">Create a Go module</a>. | |
| </aside> | |
| <p> | |
| But there's a hitch. Changing the <code>Hello</code> function's | |
| parameter from a single name to a set of names would change the function's | |
| signature. If you had already published the <code>example.com/greetings</code> | |
| module and users had already written code calling <code>Hello</code>, that | |
| change would break their programs.</p> | |
| <p> | |
| In this situation, a better choice is to write a new function with a different | |
| name. The new function will take multiple parameters. That preserves the old | |
| function for backward compatibility. | |
| </p> | |
| <ol> | |
| <li> | |
| In greetings/greetings.go, change your code so it looks like the following. | |
| <pre> | |
| 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 | |
| } | |
| <ins>// 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 | |
| }</ins> | |
| // 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))] | |
| } | |
| </pre> | |
| <p> | |
| In this code, you: | |
| </p> | |
| <ul> | |
| <li> | |
| Add a <code>Hellos</code> function whose parameter is a slice of names | |
| rather than a single name. Also, you change one of its return types from | |
| a <code>string</code> to a <code>map</code> so you can return names | |
| mapped to greeting messages. | |
| </li> | |
| <li> | |
| Have the new <code>Hellos</code> function call the existing | |
| <code>Hello</code> function. This helps reduce duplication while also | |
| leaving both functions in place. | |
| </li> | |
| <li> | |
| Create a <code>messages</code> map to associate each of the | |
| received names (as a key) with a generated message (as a value). In Go, | |
| you initialize a map with the following syntax: | |
| <code>make(map[<em>key-type</em>]<em>value-type</em>)</code>. You have | |
| the <code>Hellos</code> function return this map to the caller. For more | |
| about maps, see <a href="/blog/maps">Go maps in | |
| action</a> on the Go blog. | |
| </li> | |
| <li> | |
| Loop through the names your function received, checking that each has a | |
| non-empty value, then associate a message with each. In this | |
| <code>for</code> loop, <code>range</code> returns two values: the index | |
| of the current item in the loop and a copy of the item's value. You | |
| don't need the index, so you use the Go blank identifier (an underscore) | |
| to ignore it. For more, see | |
| <a href="/doc/effective_go.html#blank">The blank | |
| identifier</a> in Effective Go. | |
| </li> | |
| </ul> | |
| </li> | |
| <li> | |
| In your hello/hello.go calling code, pass a slice of names, then print the | |
| contents of the names/messages map you get back. | |
| <p> | |
| In hello.go, change your code so it looks like the following. | |
| </p> | |
| <pre> | |
| 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) | |
| <ins>// A slice of names. | |
| names := []string{"Gladys", "Samantha", "Darrin"} | |
| // Request greeting messages for the names. | |
| messages, err := greetings.Hellos(names)</ins> | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| <ins>// If no error was returned, print the returned map of | |
| // messages to the console. | |
| fmt.Println(messages)</ins> | |
| } | |
| </pre> | |
| <p> | |
| With these changes, you: | |
| </p> | |
| <ul> | |
| <li> | |
| Create a <code>names</code> variable as a slice type holding three | |
| names. | |
| </li> | |
| <li> | |
| Pass the <code>names</code> variable as the argument to the | |
| <code>Hellos</code> function. | |
| </li> | |
| </ul> | |
| </li> | |
| <li> | |
| At the command line, change to the directory that contains hello/hello.go, | |
| then use <code>go run</code> to confirm that the code works. | |
| <p> | |
| The output should be a string representation of the map associating names | |
| with messages, something like the following: | |
| </p> | |
| <pre> | |
| $ go run . | |
| map[Darrin:Hail, Darrin! Well met! Gladys:Hi, Gladys. Welcome! Samantha:Hail, Samantha! Well met!] | |
| </pre | |
| > | |
| </li> | |
| </ol> | |
| <p> | |
| This topic introduced maps for representing name/value pairs. It also | |
| introduced the idea of preserving backward compatibility | |
| by implementing a new function for new or changed functionality in a module. | |
| For more about backward compatibility, see | |
| <a href="/blog/module-compatibility">Keeping your modules | |
| compatible</a>. | |
| </p> | |
| <p>Next, you'll use built-in Go features to create a unit test for your code.</p> | |
| <p class="Navigation"> | |
| <a class="Navigation-prev" href="/doc/tutorial/random-greeting.html" | |
| >< Return a random greeting</a | |
| > | |
| <a class="Navigation-next" href="/doc/tutorial/add-a-test.html">Add a test ></a> | |
| </p> |