Go Zero to Hero - Bài 11: Cấu trúc rẽ nhánh: if, else if, else
Trong các ngôn ngữ như C++, Java hay JavaScript, bạn sẽ quen với việc bọc điều kiện trong cặp ngoặc đơn (). Trong Go, bạn hãy quên điều đó đi! Trình biên dịch của Go xem cặp ngoặc đơn đó là thừa thãi.
1. Cú pháp cơ bản: Sự giải thoát khỏi dấu ngoặc đơn
Cú pháp chuẩn:
package main
import "fmt"
func main() {
age := 21
// KHÔNG cần ngoặc đơn bọc điều kiện age >= 18
if age >= 18 {
fmt.Println("Hợp lệ: Đủ tuổi truy cập hệ thống.")
}
}
Nguyên tắc "Độc tài" của dấu ngoặc nhọn {:
Go cực kỳ khắt khe trong việc trình bày (nhờ gofmt). Dấu ngoặc nhọn mở { BẮT BUỘC phải nằm trên cùng một dòng với từ khóa if. Nếu bạn có thói quen gõ Enter đẩy dấu { xuống dòng dưới (phong cách K&R trong C), Go sẽ báo lỗi Syntax Error (lỗi cú pháp) và từ chối biên dịch ngay lập tức!
// LỖI! Go sẽ không cho phép biên dịch đoạn code này
if age >= 18
{
fmt.Println("Lỗi rồi!")
}
2. Cấu trúc mở rộng: if, else if và else
Việc rẽ nhiều nhánh trong Go hoàn toàn tương tự như các ngôn ngữ khác. Tuy nhiên, nguyên tắc khắt khe về vị trí của dấu ngoặc nhọn vẫn áp dụng triệt để cho từ khóa else.
func checkTicketStatus(status string) {
if status == "PAID" {
fmt.Println("Mở cổng, cho phép hành khách qua.")
} else if status == "PENDING" {
// Chú ý: } else if { phải nằm trên cùng một dòng
fmt.Println("Vui lòng thanh toán trước khi qua cổng.")
} else {
// Chú ý: } else { phải nằm trên cùng một dòng
fmt.Println("Vé không hợp lệ hoặc đã bị hủy!")
}
}
Lợi ích của sự cứng nhắc: Nếu bạn vô tình ngắt dòng trước từ khóa
else, chương trình sẽ gãy. Sự cứng nhắc này của Go thực chất là một điểm cộng khổng lồ: Nó ép 100% lập trình viên trên thế giới viết chung một định dạng, giúp việc đọc code của người khác dễ như đọc code của chính mình.
3. "Đặc sản" của Golang: Init Statement (Khai báo biến ngay trong if)
Đây chính là tính năng "sát thủ" làm nên thương hiệu của if trong Go, và là thứ bạn sẽ dùng ở 99% các dự án Backend.
Go cho phép bạn chạy một câu lệnh ngắn (thường là để khởi tạo biến hoặc gọi hàm) ngay trước khi kiểm tra điều kiện, cách nhau bởi dấu chấm phẩy ;.
Cú pháp:
if [Khởi_tạo_biến]; [Điều_kiểm_kiểm_tra] {
// ...
}
Ví dụ thực tế: Xử lý lỗi (Error Handling)
Trong Go, chúng ta không dùng try...catch. Thay vào đó, các hàm thường trả về kết quả kèm theo một biến err. Hãy xem cách Init Statement xử lý việc này gọn gàng như thế nào:
// Cách viết CŨ (Biến err bị rò rỉ ra phạm vi toàn cục của hàm)
err := processTransaction()
if err != nil {
fmt.Println("Giao dịch thất bại:", err)
}
// Tại đây, biến err vẫn tồn tại trong bộ nhớ, dễ gây nhầm lẫn cho các đoạn code phía dưới.
// ---------------------------------------------------------
// Cách viết CHUẨN GO (Init Statement)
if err := processTransaction(); err != nil {
fmt.Println("Giao dịch thất bại:", err)
// Xử lý lỗi, có thể return luôn tại đây
}
// Tới dòng này, biến err ĐÃ BỊ HỦY. Bộ nhớ sạch sẽ!
Quy tắc Sinh tử về Tầm vực (Scope):
Bất kỳ biến nào được khai báo ở phần Init Statement của if (ví dụ biến err ở trên) sẽ chỉ sống sót bên trong block { } của if đó, và mở rộng ra cả các nhánh else if, else đi kèm. Ngay khi kết thúc cấu trúc if-else, biến đó sẽ lập tức bị dọn dẹp khỏi bộ nhớ.
Điều này giúp bạn tái sử dụng những cái tên phổ biến như err, val, res hàng chục lần trong cùng một hàm mà không sợ chúng "đá" (shadow) hay ghi đè lên nhau.
Tổng kết
Chốt lại những điều cần nhớ khi dùng if trong Go:
- Vứt bỏ ngoặc đơn
()bao quanh điều kiện. - Dấu
{và} else {bắt buộc phải dính liền trên một dòng, không được ngắt dòng bừa bãi. - Tận dụng tối đa Init Statement (
if err := ...; err != nil) để gom gọn việc khởi tạo biến và giới hạn phạm vi sống (scope) của biến đó, giúp bộ nhớ sạch sẽ và tránh bug tiềm ẩn.
All rights reserved