| <!--{ |
| "Title": "Return greetings for multiple people", |
| "Path": "/doc/tutorial/greetings-multiple-people" |
| }--> |
| |
| <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 and pair values with a multiple-value output. |
| </p> |
| |
| <aside class="Note"> |
| <strong>Note:</strong> This topic is part of a multi-part tutorial that begins |
| with <a href="create-module.html">Create a Go module</a>. |
| </aside> |
| |
| <p> |
| To do this, you'll need to pass a set of names to a function that can return a |
| greeting for each of them. Changing the <code>Hello</code> function's |
| parameter from a single name to a set of names would change the function |
| signature. If you had already published the <code>greetings</code> module and |
| users had already written code calling <code>Hello</code>, that change would |
| break their programs. In this situation, a better choice is to give new |
| functionality a new name. |
| </p> |
| |
| <p> |
| In the last code you'll add with this tutorial, update the code as if you've |
| already published a version of the <code>greetings</code> module. Instead of |
| changing the <code>Hello</code> function, add a new function |
| <code>Hellos</code> that takes a set of names. Then, for the sake of |
| simplicity, have the new function call the existing one. Keeping both |
| functions in the package leaves the original for existing callers (or future |
| callers who only need one greeting) and adds a new one for callers that want |
| the expanded functionality. |
| </p> |
| |
| <ol> |
| <li> |
| In greetings/greetings.go, change your code so it looks like the following. |
| |
| <pre> |
| package greetings |
| |
| import ( |
| "errors" |
| "fmt" |
| "math/rand" |
| "time" |
| ) |
| |
| // 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> |
| |
| // Init sets initial values for variables used in the function. |
| func init() { |
| rand.Seed(time.Now().UnixNano()) |
| } |
| |
| // 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 Hellos function call the existing Hello function. This |
| leaves both functions in place. |
| </li> |
| <li> |
| Create a <code>messages</code> |
| <a href="https://blog.golang.org/maps">map</a> 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>Hello</code> function return this map to the caller. |
| </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 |
| <a href="https://golang.org/doc/effective_go.html#blank" |
| >blank identifier (an underscore)</a |
| > |
| to ignore it. |
| </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"}</ins> |
| |
| // 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) |
| } |
| </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 run hello.go 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 hello.go |
| 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 |
| <a href="https://blog.golang.org/module-compatibility" |
| >preserving backward compatibility</a |
| > |
| by implementing a new function for new or changed functionality in a module. |
| In the tutorial's <a href="add-a-test.html">next topic</a>, you'll use |
| built-in features to create a unit test for your code. |
| </p> |
| |
| <p class="Navigation"> |
| <a class="Navigation-prev" href="random-greeting.html" |
| >< Return a random greeting</a |
| > |
| <a class="Navigation-next" href="add-a-test.html">Add a test ></a> |
| </p> |