返回多人問候語

在您的模組程式碼中要做的最後一些更改是,您將新增對一次請求獲取多人問候語的支援。換句話說,您將處理一個多值輸入,然後將該輸入中的值與多值輸出配對。為此,您需要將一組名稱傳遞給一個可以為其中每個人返回問候語的函式。

但是有一個問題。將 Hello 函式的引數從單個名稱更改為一組名稱將改變函式的簽名。如果您已經發布了 example.com/greetings 模組,並且使用者已經編寫了呼叫 Hello 的程式碼,那麼此更改將破壞他們的程式。

在這種情況下,更好的選擇是編寫一個具有不同名稱的新函式。新函式將接受多個引數。這可以保留舊函式以實現向後相容。

  1. 在 greetings/greetings.go 中,將您的程式碼更改為如下所示。
    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
    }
    
    // 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
    }
    
    // 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,以便您可以返回名稱與問候訊息的對映。
    • 讓新的 Hellos 函式呼叫現有的 Hello 函式。這有助於減少重複,同時也讓兩個函式都保留下來。
    • 建立一個 messages 地圖,將每個收到的名稱(作為鍵)與生成的訊息(作為值)關聯起來。在 Go 中,您可以使用以下語法初始化地圖:make(map[key-type]value-type)。您讓 Hellos 函式將此地圖返回給呼叫者。有關地圖的更多資訊,請參閱 Go 部落格上的 Go maps in action
    • 遍歷函式收到的名稱,檢查每個名稱是否具有非空值,然後將訊息與每個名稱關聯起來。在此 for 迴圈中,range 返回兩個值:迴圈中當前項的索引和該項值的副本。您不需要索引,因此您使用 Go 的空識別符號(下劃線)來忽略它。有關更多資訊,請參閱 Effective Go 中的 空識別符號
  2. 在您的 hello/hello.go 呼叫程式碼中,傳遞一個名稱切片,然後列印您收到的名稱/訊息地圖的內容。

    在 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. 在命令列中,切換到包含 hello/hello.go 的目錄,然後使用 go run 來確認程式碼是否正常工作。

    輸出應該是一個字串表示的地圖,將名稱與訊息關聯起來,類似如下內容

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

本主題介紹了用於表示名稱/值對的地圖。它還介紹了透過為模組中的新功能或更改的功能實現新函式來維護向後相容性的概念。有關向後相容性的更多資訊,請參閱 保持您的模組相容

接下來,您將使用內建的 Go 功能為您的程式碼建立單元測試。