Skip to main content

[Go] := đôi khi không gán giá trị

Tạo variable (biến) trong Go

Go có 2 cách để khai báo và khởi tạo giá trị cho variable:

var x int // declare
x = 42 // init

có thể viết gọn lại

var x int = 42

Hoặc cú pháp ngắn "short declaration":

x := 42

Short declaration rules

Short declaration := ngắn hơn, được ưa chuộng, nhưng cũng kèm theo không ít chú ý mà ít ai để ý.

package main
import (
    "fmt"
    "os"
)
func main() {
    i, err := os.Open("/etc/passwd")
    i, err := os.Open("/etc/passwd")
    fmt.Printf("i %v err %v\n", i, err)
}

Code này không compile với error: no new variables on left side of :=, bên trái := luôn phải có variable mới. Code này compile ok:

func main() {
    i, err := os.Open("/etc/passwd")
    f, err := os.Open("/etc/passwd")
    fmt.Printf("i %v f %v err %v\n", i, f, err)
}

ở đây có var f mới, còn var err cũ được gán cho giá trị mới. Bằng chứng err cũ có thể test:

func main() {
    i, _ := os.Open("/etc/passwd")
    var err int = 42
    f, err := os.Open("/etc/passwd")
    fmt.Printf("i %v f %v err %v\n", i, f, err)
}

không compile với error: cannot use os.Open("/etc/passwd") (value of type error) as int value in assignment, err cũ có kiểu int, nên không thể gán giá trị kiểu error.

Đoạn code sau rất phổ biến trong lập trình web, tạo 1 global var DB client:

var db *gorp.DbMap

//Init ...
func Init() {
    dbinfo := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable", os.Getenv("DB_USER"), os.Getenv("DB_PASS"), os.Getenv("DB_NAME"))
    db, err := ConnectDB(dbinfo)
    if err != nil {
        log.Fatal(err)
    }

err là var mới, còn db là var mới hay var cũ được gán giá trị?

Theo những ví dụ trên, có thể mong chờ db là var cũ được gán cho giá trị. Nhưng theo effective go:

In a := declaration a variable v may appear even if it has already been declared, provided: if v is already declared in an outer scope, the declaration will create a new variable.

db trong Init là var db mới, shadow (che mất) var db bên ngoài, db bên ngoài vẫn là nil. Để fix bug này, không dùng := mà viết:

    var err error
    db, err = ConnectDB(dbinfo)

Kết luận

Go vốn dài dòng, mà chỗ ngắn cũng toàn chú ý, cộng đồng mạng tạo hẳn 6 luật để dùng := https://stackoverflow.com/questions/17891226/difference-between-and-operators-in-go/45654233#45654233

Go thật đơn giản, ha!

Hết.

HVN at http://pymi.vn and https://www.familug.org.

Ủng hộ tác giả 🍺

Comments

Popular posts from this blog

Tài liệu và hướng dẫn học Python

Để tiết kiệm thời gian, tốt nhất là đi học PyMI Updated: 130617 Sau đây là các tài liệu khuyên dùng: Vì nhiều lý do, nên học python2.7 tại thời điểm hiện tại (giờ là tháng 6/2013 - muốn biết tại sao thì tự tìm hiểu) python 3.5+ (giờ là tháng 2/2017) Chuẩn bị: 1. biết bật tắt máy 2. biết cài python 3. tập gõ 10 ngón - gõ 2 ngón hay 1 ngón cũng không sao, nhưng 10 ngón là cách dễ nhất để gõ nhanh nhất. Tài liệu - Nên dùng tài liệu tại trang chủ của Python làm chính, tham khảo thêm các tài liệu khác tại http://www.familug.org/2016/12/free-ebook.html Căn bản, mới học 1.1 Python PyMI.vn https://pymi.vn/tutorial/ 1.2. Python offical tutorial kết hợp làm bài tập trên HackerRank  (đề bài bằng tiếng Anh, nhưng Google translate 1 lúc cũng ra vì có nhiều ví dụ mẫu đi kèm). Học viên của Pymi.vn có rất nhiều học viên đã tự học với Learn Python the hard way nhưng chưa thấy ai thành công cả. Hai link dưới nên đọc sau khi đã nắm được những phần cơ bản của ngôn ngữ pytho...

The PyMiers

New FAMILUG