为多人返回问候语
在您对模块代码进行的最后修改中,您将添加支持在一次请求中为多人获取问候语的功能。换句话说,您需要处理多值输入,然后将输入中的值与多值输出进行配对。为此,您需要将一组名字传递给一个能够为每个名字返回问候语的函数。
但这里有个问题。将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 } // 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 } // 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[键类型]值类型)。您让Hellos函数将此映射返回给调用者。有关映射的更多信息,请参阅Go博客上的Go maps in action。 -
遍历函数接收到的名字,检查每个名字是否具有非空值,然后为每个名字关联一条消息。在此
for循环中,range返回两个值:循环中当前项的索引和该项值的副本。您不需要索引,因此使用Go的空标识符(下划线)忽略它。更多信息请参阅Effective Go中的The blank identifier。
-
添加了一个
-
在您的 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变量,作为包含三个名字的切片类型。 -
将
names变量作为参数传递给Hellos函数。
-
创建了一个
-
在命令行中,切换到包含 hello/hello.go 的目录,然后使用
go run确认代码是否正常工作。输出应该是一个将名字与消息关联起来的映射的字符串表示,类似于以下内容:
$ go run . map[Darrin:Hail, Darrin! Well met! Gladys:Hi, Gladys. Welcome! Samantha:Hail, Samantha! Well met!]
本主题介绍了使用映射来表示名称/值对的概念。同时也阐述了通过在新功能或功能变更时,为模块实现新函数以保持向后兼容性的思路。关于向后兼容性的更多信息,请参阅保持模块兼容性。 接下来,您将使用Go语言内置功能为代码创建单元测试。