KHOÁ HỌC Phần 2 — 20% còn lại Ecosystem thực chiến

Ecosystem thực chiến

F1. Go Modules

# Khởi tạo project
go mod init github.com/user/project

# Thêm thư viện
go get github.com/gin-gonic/gin

# Dọn dẹp dependency thừa
go mod tidy

# Xem cây phụ thuộc
go mod graph

File go.mod

module github.com/user/project

go 1.22

require (
    github.com/gin-gonic/gin v1.9.1
    golang.org/x/sync v0.5.0
)

go.sum = checksum để đảm bảo build có thể tái tạo (reproducible).

F2. Testing

File math_test.go (đặt cạnh math.go)

package math

import "testing"

func TestAdd(t *testing.T) {
    got := Add(2, 3)
    if got != 5 {
        t.Errorf("Add(2,3) = %d; muốn 5", got)
    }
}

Table-driven test (chuẩn Go)

func TestAdd(t *testing.T) {
    tests := []struct{
        name       string
        a, b, want int
    }{
        {"cộng dương", 2, 3, 5},
        {"cộng âm",   -1, -2, -3},
        {"với 0",      0, 5, 5},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if got := Add(tt.a, tt.b); got != tt.want {
                t.Errorf("got %d, want %d", got, tt.want)
            }
        })
    }
}

Benchmark

func BenchmarkAdd(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Add(2, 3)
    }
}

Chạy: go test -bench=.

Coverage

go test -cover
go test -coverprofile=cover.out && go tool cover -html=cover.out

F3. JSON

Marshal — Struct → JSON

type User struct {
    Name string `json:"name"`
    Age  int    `json:"age,omitempty"`
}

u := User{Name: "Alice", Age: 30}
b, _ := json.Marshal(u)
fmt.Println(string(b)) // {"name":"Alice","age":30}

Unmarshal — JSON → Struct

data := []byte(`{"name":"Bob","age":25}`)
var u User
json.Unmarshal(data, &u) // ⚠️ nhớ truyền con trỏ

Field ẩn/tuỳ chọn

`json:"-"`              // Bỏ qua
`json:"name,omitempty"` // Bỏ nếu zero value
`json:"name,string"`    // Ép sang string

F4. HTTP server & client

Server siêu ngắn

func main() {
    http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Xin chào,", r.URL.Query().Get("name"))
    })
    http.ListenAndServe(":8080", nil)
}

Client

resp, err := http.Get("https://api.example.com/users")
if err != nil { log.Fatal(err) }
defer resp.Body.Close()

body, _ := io.ReadAll(resp.Body)

JSON POST

data, _ := json.Marshal(map[string]string{"key": "value"})
resp, _ := http.Post("https://api...", "application/json", bytes.NewBuffer(data))

F5. File I/O

Đọc toàn bộ file

data, err := os.ReadFile("config.yaml")

Ghi toàn bộ file

os.WriteFile("out.txt", []byte("hello"), 0644)

Đọc từng dòng (file lớn)

f, _ := os.Open("big.log")
defer f.Close()

scanner := bufio.NewScanner(f)
for scanner.Scan() {
    fmt.Println(scanner.Text())
}
← Concurrency nâng cao