+1

SO SÁNH = VÀ := TRONG GOLANG: RANH GIỚI GIỮA GÁN VÀ KHAI BÁO

trong Golang, sự khác biệt giữa = và := không chỉ nằm ở cú pháp viết tắt cho gọn tay, mà nó quyết định trực tiếp đến vòng đời, phạm vi hoạt động (scope) và cách bộ biên dịch cấp phát bộ nhớ cho biến. Hiểu sai hai toán tử này là nguyên nhân hàng đầu dẫn đến lỗi "Shadowing" khét tiếng khi xử lý các luồng gRPC hay truy vấn database.

Dưới đây là bài viết mổ xẻ chi tiết bản chất và cách phân biệt hai toán tử này.

Trong ngôn ngữ Go (Golang), việc phân định rạch ròi giữa khởi tạo vùng nhớ mới (:=) và cập nhật dữ liệu (=) là bước kiểm soát bộ nhớ nền tảng. Trong các dự án microservices, việc lạm dụng := bừa bãi trong các vòng lặp hoặc khối lệnh rẽ nhánh là nguyên nhân hàng đầu gây ra rò rỉ dữ liệu logic mà trình biên dịch không hề cảnh báo.


1. := (Short Variable Declaration - Khai báo và khởi tạo ngắn gọn)

Toán tử := thực chất là một "cú lừa" cú pháp (syntactic sugar) kết hợp hai hành động cùng lúc: Khai báo một biến hoàn toàn mới và gán giá trị khởi tạo cho nó. Go sẽ tự động nội suy kiểu dữ liệu (Type Inference) dựa trên giá trị được gán.

  • Tính chất cốt lõi: Bắt buộc phải tạo ra ít nhất một biến MỚI ở phía bên trái.
  • Phạm vi giới hạn: Chỉ được phép sử dụng bên trong thân hàm (function body). Tuyệt đối không được dùng ở cấp độ package (Global scope).
func fetchUserData() {
    // Khai báo biến mới 'userID' và gán giá trị 105 (Go tự hiểu đây là int)
    userID := 105 
    
    // Khai báo nhiều biến cùng lúc
    name, age := "Hieu", 22 
}

2. = (Assignment Operator - Toán tử gán)

Toán tử = chỉ làm đúng một nhiệm vụ duy nhất: Cập nhật giá trị mới cho một biến ĐÃ TỒN TẠI từ trước. Nó hoàn toàn không có khả năng sinh ra vùng nhớ hay biến mới.

  • Tính chất cốt lõi: Biến ở phía bên trái bắt buộc phải được khai báo trước đó (thông qua từ khóa var hoặc đã dùng := trước đó).
  • Phạm vi: Có thể dùng ở bất cứ đâu (trong hàm hoặc ngoài hàm để gán giá trị cho biến global).
var globalStatus string = "INIT" // Khai báo rõ ràng với var và =

func updateStatus() {
    var count int
    count = 10 // Cập nhật biến đã tồn tại bằng =

    name := "Admin"
    name = "SuperAdmin" // Cập nhật lại giá trị bằng =
}

3. Bảng So Sánh Nhanh

Tiêu chí := (Khai báo ngắn) = (Gán giá trị)
Bản chất Khai báo biến mới + Gán giá trị Cập nhật giá trị cho biến cũ
Biến bên trái Phải có ít nhất 1 biến CHƯA tồn tại trong scope hiện tại Bắt buộc phải ĐÃ tồn tại
Nội suy kiểu dữ liệu Có (Tự động nhận diện int, string,...) Không (Biến đã bị fix cứng kiểu từ trước)
Vị trí sử dụng Chỉ dùng bên trong hàm Dùng được ở mọi nơi

4. Bẫy Tử Thần Trong Thực Chiến: Variable Shadowing Với Biến err

Khi xử lý các logic backend phức tạp, các lập trình viên Go rất hay dùng := để hứng lỗi từ các hàm trả về nhiều kết quả. Nếu không cẩn thận, bạn sẽ vô tình tạo ra một biến err cục bộ che khuất (shadow) biến err gốc bên ngoài, dẫn đến việc hàm luôn báo thành công dù bên trong thực chất đã bị lỗi.

Ví dụ một đoạn code lỗi kinh điển:

func processTransaction(txID string) error {
    var err error // Biến err gốc (scope của toàn hàm processTransaction)

    if txID != "" {
        // 💥 BẪY CHẾT NGƯỜI TẠI ĐÂY:
        // Dùng := bên trong block 'if' sẽ tạo ra một biến 'result' MỚI 
        // và một biến 'err' MỚI tinh chỉ sống bên trong khối 'if' này.
        result, err := queryDatabase(txID) 
        if err != nil {
            log.Println("Lỗi query:", err)
            // Biến err cục bộ này sẽ biến mất khi thoát khỏi khối if!
        }
        _ = result
    }

    // Biến err gốc bên ngoài chưa từng bị chạm tới, giá trị vẫn là nil!
    return err 
}

Cách khắc phục:

Để sửa lỗi trên, bạn phải khai báo biến result từ trước, sau đó dùng toán tử = để ép Go tái sử dụng biến err gốc bên ngoài khối if.

func processTransaction(txID string) error {
    var err error 
    var result string // Khai báo trước

    if txID != "" {
        // Dùng = để cập nhật biến đã tồn tại, không sinh biến mới
        result, err = queryDatabase(txID) 
        // ...
    }
    return err 
}

All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.