好了,这是最后一次修改这个模块代码, 使代码支持在一次请求问候多个人,换句话说,你将把多个输入值和内部的值匹配起来,产生多个输出值.为了达到这个目的,你需要将一组人名传入函数,然后给每个人返回问候语.
不过呢,这有一点小困难,将hello函数的入参,由单一名称改为一组名称,这叫改变函数的签名<注:我认为翻译成函数特征比较容易理解,但是其他语言都把signature叫做签名,一般来说,对于多数编程语言,函数的名称和入参共同标识了这个函数的唯一性,对于面向对象的语言,多态性就是通过改变函数参数来实现>.如果你已经将example.com/greeting模块发行,并且有人已经调用hello模块了,那么本次的改变,将会对导致他们的程序无法运行.
这这种情况下,最好的选择就是另写一个函数,并命名为其他.这个新函数将拥有多个参数,这将保留旧函数以实现向后兼容性.
在greetings/greetings.go,用下面代码替换
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 } // 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 } // 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))] }
这片代码中:
- 增加了一个hellos函数,它的参数是一个名称切片,而不是单一名字.此外,又将返回类型从string改为map,这样你就能把问候语和名称对应起来
- 让新的hello函数调用老的hello函数,这样能减少重复工作,并且同时保留这两个功能
- 创建了一个messages 映射,以便将收到的名字(作为key)和产生的消息(作为value)关联,在Go中,使用下面的语法初始化一个映射: make(map[key-type] value-type). hellos函数会把这个映射返回给调用者. 更多关于maps高级知识,请参看go maps in action
- 遍历函数收到的名字,检查每个名字不是空值,然后给它们分派消息,在这个for-range<注:相当于foreach,>循环中返回了两个值:当前项目的索引和项目的值,其实你并不需要索引,所以就用Go 的blank标识符("_"下划线)忽略了它. 可以看看 GO本质论中的 空标识符 的细节描述
2.在hello/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) }
上面代码,做了这些调整:
- 创建了一个names变量,其类型是切片,用来装载三个名字
- 将names变量作为参数传递给hellos函数
3.在命令行中运行代码.