• English
  • 返回多人的問候

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

    注意: 本文是系列教學的一部分,該系列始於 建立 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 的內建功能為你的程式碼建立單元測試。