Go语言基地
Tutorilas创建模块

返回多人的问候

在你对模块代码进行的最后一次更改中,你将添加对一次请求中获取多人的问候的支持。换句话说,你将处理多值输入,然后将该输入中的值与多值输出配对。为此,你需要将一组名字传递给一个函数,该函数可以为每个人返回一条问候语。

注意: 本文是系列教程的一部分,该系列始于 创建 Go 模块

但这里有一个问题。将 Hello 函数的参数从单个名字更改为一组名字会改变函数的签名。如果你已经发布了 example.com/greetings 模块,并且用户已经编写了调用 Hello 的代码,那么这个更改会破坏他们的程序。

在这种情况下,更好的选择是编写一个具有不同名称的新函数。新函数将接受多个参数。这样可以保留旧函数以实现向后兼容性。

步骤

  1. 使用以下代码更新你的 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[key-type]value-type)。你让 Hellos 函数将此映射返回给调用者。有关映射的更多信息,请参阅 Go 博客上的 Go 映射实战
  • 遍历函数接收到的名字,检查每个名字是否非空,然后为每个名字关联一条消息。在这个 for 循环中,range 返回两个值:当前项在循环中的索引和该项值的副本。你不需要索引,因此使用 Go 空白标识符(下划线)来忽略它。有关更多信息,请参阅 Effective Go 中的 空白标识符
  1. 更新你的 hello/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 函数的参数传递。
  1. 从命令行运行代码 以验证其是否正常工作:
$ go run .

输出应该是将名字与消息关联的映射的字符串表示,类似于以下内容:

map[Darrin:Hail, Darrin! Well met! Gladys:Hi, Gladys. Welcome! Samantha:Hail, Samantha! Well met!]

总结

本主题介绍了用于表示名称/值对的映射。它还介绍了通过为模块中新的或更改的功能实现新函数来保留向后兼容性的思想。有关向后兼容性的更多信息,请参阅 保持模块兼容

接下来,你将使用 Go 的内建功能为你的代码创建单元测试。

On this page