為多個人傳回問候語

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

但有一個問題。將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函式,其參數是名稱的區塊,而非單一名稱。此外,您將其其中一個回傳類型從字串變更為對應,以便您可以回傳對應到問候訊息的名稱。
    • 讓新的Hellos函式呼叫現有的Hello函式。這有助於減少重複,同時保留兩個函式。
    • 建立一個訊息對應,將每個收到的名稱 (做為金鑰) 與產生的訊息 (做為值) 關聯。在 Go 中,您使用下列語法初始化對應:make(map[金鑰類型]值類型)。您讓Hellos函式將此對應回傳給呼叫者。如需有關對應的詳細資訊,請參閱 Go 部落格上的Go 對應實際應用
    • 迴圈處理函式收到的名稱,檢查每個名稱是否具有非空值,然後將訊息與每個名稱關聯。在此for迴圈中,範圍會回傳兩個值:迴圈中目前項目的索引和項目值的副本。您不需要索引,因此使用 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 功能為您的程式碼建立單元測試。