Menu

if else trong Golang: cú pháp, khởi tạo và if err != nil

Cách if, else if và else hoạt động trong Go: không cần ngoặc tròn, bắt buộc có ngoặc nhọn, câu lệnh if kèm mệnh đề khởi tạo và phạm vi của nó, thành ngữ if err != nil, và return sớm thay cho lồng nhau nhiều tầng.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

if của Go không có ngoặc tròn quanh điều kiện (condition), luôn bắt buộc có ngoặc nhọn, và có thể bắt đầu bằng một câu lệnh ngắn khai báo biến có phạm vi trong if.

Các điều kiện được kiểm tra từ trên xuống và nhánh đúng đầu tiên sẽ chạy. else if và else là tùy chọn.

Quy tắc cú pháp

Ba quy tắc khác với C, Java và JavaScript:

  1. Không có ngoặc tròn quanh điều kiện. if (x > 5) vẫn biên dịch được, nhưng gofmt sẽ bỏ ngoặc đi.
  2. Bắt buộc có ngoặc nhọn, kể cả khi chỉ có một câu lệnh. Không có dạng không ngoặc như if x > 5 return.
  3. else nằm cùng dòng với dấu ngoặc nhọn đóng. Go chèn dấu chấm phẩy sau một } ở cuối dòng, nên đoạn này lỗi:
if x > 5 {
	fmt.Println("big")
}
else {
	fmt.Println("small")
}
syntax error: unexpected keyword else, expected }

Hãy viết } else { trên một dòng.

Điều kiện phải là một bool. Go không coi 0, "" hay nil là false, nên if count {} và if name {} không biên dịch được. Hãy so sánh rõ ràng: if count > 0, if name != "", if user != nil.

Kết hợp điều kiện bằng && (và), || (hoặc) và ! (phủ định). Cả && và || đều đánh giá ngắn mạch, nhờ vậy việc kiểm tra nil là an toàn:

if user != nil && user.IsAdmin() {
	// user.IsAdmin() is only called when user is not nil
}

if kèm câu lệnh khởi tạo

Một if có thể chạy một câu lệnh ngắn trước điều kiện, ngăn cách bằng dấu chấm phẩy. Biến khai báo trong đó thấy được ở mọi nhánh của if đó, và không thấy được ở đâu sau nó:

Mẫu này giữ các biến sống ngắn ra khỏi phạm vi xung quanh. Nó xuất hiện liên tục với việc tra map (v, ok := m[k]), type assertion (s, ok := v.(string)) và lỗi.

Mặt trái: nếu bạn cần giá trị đó sau if, hãy khai báo nó trước. Một lỗi hay gặp là đặt kết quả vào câu lệnh khởi tạo rồi lại cố dùng nó ở bên dưới.

Thành ngữ if err != nil

Các hàm có thể thất bại trả về error ở cuối. Hãy kiểm tra nó ngay, xử lý hoặc trả nó về, rồi tiếp tục nhánh chạy bình thường mà không thụt lề:

Để ý rằng không có else sau if err != nil { return ... }. Phong cách Go là xử lý lỗi, return, và để luồng bình thường nằm sát lề trái. Trang xử lý lỗi trình bày việc bọc lỗi và kiểm tra kiểu lỗi.

Return sớm thay cho lồng nhau

Các khối if lồng nhau nhiều tầng rất khó đọc. Hãy đảo điều kiện và return sớm; khi đó mỗi lần kiểm tra đọc như một chốt chặn:

// Nested
func canCheckout(u *User, cart *Cart) bool {
	if u != nil {
		if u.Verified {
			if len(cart.Items) > 0 {
				return true
			}
		}
	}
	return false
}

// Guards
func canCheckout(u *User, cart *Cart) bool {
	if u == nil || !u.Verified {
		return false
	}
	if len(cart.Items) == 0 {
		return false
	}
	return true
}

Lập trình viên Go gọi đây là giữ nhánh chạy bình thường sát lề trái. Các linter như revive đánh dấu một else đứng sau khối lệnh kết thúc bằng return, vì else đó chỉ thêm thụt lề vô ích.

if/else và switch

Một chuỗi else if dài so sánh một giá trị với nhiều trường hợp sẽ dễ đọc hơn khi viết bằng switch. Một switch không có biểu thức thay được cho chuỗi if/else if với các điều kiện bất kỳ:

switch {
case score >= 90:
	return "A"
case score >= 80:
	return "B"
default:
	return "F"
}

Dùng if cho một hoặc hai nhánh, và switch khi có từ ba nhánh trở lên.

Không có toán tử ba ngôi

Go không có cond ? a : b. Hãy gán bằng if:

label := "odd"
if n%2 == 0 {
	label = "even"
}

Trang toán tử ba ngôi giải thích lý do và đưa ra các cách thay thế.

Lỗi thường gặp

  • Che biến bằng :=. if x, err := f(); err == nil { ... } khai báo một x mới chỉ dành cho if. x ở bên ngoài không được cập nhật.
  • Gán trong điều kiện. if x = 5 {} là lỗi biên dịch (cannot use assignment x = 5 as value), không phải một bug âm thầm như trong C. Hãy dùng ==.
  • So sánh số thực bằng ==. if total == 0.3 thất bại với giá trị tính toán ra. Hãy so sánh với một sai số cho phép.
  • Kiểm tra nhầm lỗi. Sau a, err := f() và b, err := g(), hãy đảm bảo mỗi if err != nil nằm ngay sau lời gọi của nó.

Câu hỏi thường gặp

Viết if else trong Go như thế nào?

Không có ngoặc tròn quanh điều kiện, và luôn bắt buộc có ngoặc nhọn:

if x > 10 {
	fmt.Println("big")
} else if x > 5 {
	fmt.Println("medium")
} else {
	fmt.Println("small")
}

else phải nằm cùng dòng với dấu ngoặc nhọn đóng của khối lệnh trước.

Câu lệnh if kèm câu lệnh khởi tạo trong Go là gì?

Một câu lệnh ngắn đứng trước điều kiện, ngăn cách bằng dấu chấm phẩy: if n, err := strconv.Atoi(s); err != nil { ... }. Các biến khai báo ở đó chỉ tồn tại bên trong if và các nhánh else if, else của nó, nhờ vậy chúng không lọt ra phần còn lại của hàm.

Có viết được if trên một dòng trong Go không?

Không thể nếu thiếu ngoặc nhọn. if ok return và if (ok) x = 1; đều là lỗi cú pháp. Dạng ngắn nhất là if ok { return }, và gofmt sẽ đưa phần thân xuống dòng riêng. Go cũng không có toán tử ba ngôi, nên một giá trị có điều kiện cần if/else hoặc một hàm trợ giúp nhỏ.

Vì sao Go dùng if err != nil ở khắp nơi?

Go không có exception. Các hàm có thể thất bại trả về một error làm kết quả cuối cùng, và nơi gọi kiểm tra nó ngay bằng if err != nil. Sự lặp lại đó là cái giá để mọi điểm có thể lỗi đều hiện rõ ngay tại chỗ nó xảy ra.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu