☰ Mục lục series
Tài liệu Go tiếng Việt
  1. Bắt đầu (Getting started)
    1. Tổng quan
    2. Tải về và cài đặt
    3. Bắt đầu với Go
    4. Quản lý các bản cài đặt Go
    5. Plugin trình soạn thảo và IDE
  2. Dạo quanh Go (A Tour of Go)
    1. Chào mừng
    2. Package, biến và hàm
    3. Điều khiển luồng
    4. Struct, slice và map
    5. Method và interface
    6. Generics
    7. Xử lý đồng thời
  3. Hướng dẫn (Tutorials)
    1. Danh sách hướng dẫn
    2. Tạo một Go module
    3. Gọi mã của bạn từ một module khác
    4. Trả về và xử lý lỗi
    5. Trả về lời chào ngẫu nhiên
    6. Trả về lời chào cho nhiều người
    7. Thêm một test
    8. Biên dịch và cài đặt ứng dụng
    9. Kết luận
    10. Bắt đầu với workspace nhiều module
    11. Phát triển RESTful API với Go và Gin
    12. Truy cập cơ sở dữ liệu quan hệ
    13. Bắt đầu với generics
    14. Bắt đầu với fuzzing
    15. Làm việc với JSON
    16. Tìm và sửa các dependency có lỗ hổng với govulncheck
    17. Tìm và khắc phục phụ thuộc có lỗ hổng với VS Code Go
    18. Viết ứng dụng web
  4. Viết code Go
    1. Cách viết mã Go
    2. Effective Go
    3. Doc Comment trong Go
  5. Module
    1. Phát triển và publish module
    2. Quản lý phụ thuộc
    3. Tổ chức một module Go
    4. Quản lý mã nguồn của module
    5. Cách đánh số phiên bản module
    6. Quy trình phát hành và đánh phiên bản module
    7. Publish một module
    8. Phát triển một bản cập nhật major version
    9. Tham chiếu tệp go.mod
    10. Ngừng hỗ trợ 'go get' cho việc cài đặt tệp thực thi
  6. Cơ sở dữ liệu (Database)
    1. Truy cập cơ sở dữ liệu quan hệ
    2. Mở một handle cơ sở dữ liệu
    3. Thực thi câu lệnh SQL không trả về dữ liệu
    4. Truy vấn dữ liệu
    5. Dùng prepared statement
    6. Thực thi transaction
    7. Huỷ các thao tác đang chạy
    8. Quản lý kết nối
    9. Tránh rủi ro SQL injection
  7. Chẩn đoán và hiệu năng
    1. Chẩn đoán
    2. Hướng dẫn về Go Garbage Collector
    3. Tối ưu hoá dựa trên profile
    4. Data Race Detector
    5. Gỡ lỗi mã Go bằng GDB
    6. Hỗ trợ coverage profiling cho integration test
  8. Bảo mật (Security)
    1. Tổng quan bảo mật
    2. Thực hành tốt về bảo mật cho lập trình viên Go
    3. Quản lý lỗ hổng trong Go
    4. Cơ sở dữ liệu lỗ hổng của Go
    5. Quét lỗ hổng trong IDE
    6. Chính sách CNA của Go
    7. Go Fuzzing
    8. Chi tiết kỹ thuật của Go Fuzzing
    9. Chính sách bảo mật của Go
    10. Threat Model của Go
    11. Các quyết định về bảo mật của Go
    12. Tuân thủ FIPS 140-3
  9. Công cụ và toolchain
    1. Tài liệu về các lệnh
    2. Về lệnh go
    3. Go Toolchains
    4. Telemetry của Go
    5. Cài đặt Go từ mã nguồn
    6. Cài đặt và sử dụng gccgo
  10. Tham khảo
    1. Câu hỏi thường gặp (FAQ)
    2. Go 1 và tương lai của các chương trình Go
    3. Hướng dẫn chuyển đổi sang encoding/json/v2
    4. Hướng dẫn đóng góp
    5. Đóng góp cho frontend gccgo
  11. Phụ lục
    1. Bảng thuật ngữ
Hướng dẫn (Tutorials)

Trả về lời chào cho nhiều người

Bản dịch từ go.dev/doc/tutorial/greetings-multiple-people

Trong lần thay đổi cuối cùng với mã của module, bạn sẽ bổ sung khả năng lấy lời chào cho nhiều người trong cùng một yêu cầu. Nói cách khác, bạn sẽ xử lý đầu vào gồm nhiều giá trị, rồi ghép các giá trị đó với đầu ra cũng gồm nhiều giá trị. Để làm vậy, bạn cần truyền một tập tên vào một hàm có thể trả về lời chào cho từng người.

Lưu ý: Chủ đề này là một phần của loạt hướng dẫn nhiều phần, bắt đầu từ Tạo một Go module.

Nhưng có một vướng mắc. Việc đổi tham số của hàm Hello từ một tên đơn lẻ thành một tập tên sẽ làm thay đổi chữ ký của hàm. Nếu bạn đã publish module example.com/greetings và người dùng đã viết mã gọi Hello, thay đổi đó sẽ làm hỏng chương trình của họ.

Trong tình huống này, lựa chọn tốt hơn là viết một hàm mới với tên khác. Hàm mới sẽ nhận nhiều tham số. Cách này giữ lại hàm cũ để đảm bảo tương thích ngược.

  1. Trong greetings/greetings.go, sửa mã của bạn thành như sau.

    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))]
    }

    Trong đoạn mã này, bạn:

    • Thêm hàm Hellos có tham số là một slice các tên thay vì một tên đơn lẻ. Bạn cũng đổi một trong các kiểu trả về từ string thành map để có thể trả về các tên được ánh xạ tới thông điệp chào.
    • Cho hàm Hellos mới gọi lại hàm Hello đã có. Điều này giúp giảm trùng lặp mà vẫn giữ được cả hai hàm.
    • Tạo map messages để gắn mỗi tên nhận được (làm khoá) với một thông điệp được sinh ra (làm giá trị). Trong Go, bạn khởi tạo map bằng cú pháp sau: make(map[kiểu-khoá]kiểu-giá-trị). Bạn cho hàm Hellos trả về map này cho phía gọi. Tìm hiểu thêm về map tại Go maps in action trên blog của Go.
    • Lặp qua các tên mà hàm nhận được, kiểm tra từng tên có giá trị khác rỗng, rồi gắn một thông điệp cho mỗi tên. Trong vòng lặp for này, range trả về hai giá trị: chỉ số của phần tử hiện tại trong vòng lặp và một bản sao giá trị của phần tử. Bạn không cần chỉ số, nên bạn dùng blank identifier của Go (dấu gạch dưới) để bỏ qua nó. Tìm hiểu thêm tại The blank identifier trong Effective Go.
  2. Trong mã phía gọi hello/hello.go, hãy truyền vào một slice các tên, rồi in ra nội dung của map tên/thông điệp mà bạn nhận lại.

    Trong hello.go, sửa mã của bạn thành như sau.

    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)
    }

    Với những thay đổi này, bạn:

    • Tạo biến names kiểu slice chứa ba tên.
    • Truyền biến names làm đối số cho hàm Hellos.
  3. Tại dòng lệnh, chuyển sang thư mục chứa hello/hello.go, rồi dùng go run để xác nhận mã hoạt động.

    Kết quả in ra sẽ là dạng biểu diễn chuỗi của map gắn tên với thông điệp, đại khái như sau:

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

Chủ đề này đã giới thiệu map để biểu diễn các cặp tên/giá trị. Nó cũng giới thiệu ý tưởng giữ tương thích ngược bằng cách hiện thực một hàm mới cho chức năng mới hoặc chức năng thay đổi trong module. Tìm hiểu thêm về tương thích ngược tại Keeping your modules compatible.

Tiếp theo, bạn sẽ dùng các tính năng có sẵn của Go để viết unit test cho mã của mình.

Nội dung gốc: Go Documentation © The Go Authors, giấy phép CC BY 3.0. Bản dịch và ghi chú: Lê Văn Dũng.