Câu lệnh switch so sánh một giá trị với danh sách các case và chạy case khớp đầu tiên. Khác với C, Java và JavaScript, một case trong Go không rơi xuống case tiếp theo, nên không có break nào để bạn quên.
Các case được kiểm tra từ trên xuống dưới, và chỉ case khớp đầu tiên được chạy. default chạy khi không có gì khớp; nó là tùy chọn và có thể đặt ở bất kỳ đâu trong danh sách, dù theo quy ước thường đặt cuối cùng.
Nhiều giá trị trong một case
case "sat", "sun": khớp với một trong hai giá trị. Đây là cách Go diễn đạt điều mà C làm bằng các case rỗng xếp chồng. Kiểu nào so sánh được cũng dùng được: chuỗi, số, rune, boolean, con trỏ, và các kiểu đặt tên như enum:
Hai case có cùng giá trị hằng là lỗi biên dịch:
./main.go:10:7: duplicate case 1 (constant of type int) in expression switch
./main.go:8:7: previous case
Switch không có điều kiện
Bỏ biểu thức đi thì mỗi case trở thành một phép kiểm tra boolean. Đây là dạng gọn gàng hơn của Go cho một chuỗi if/else if dài:
switch { là cách viết tắt của switch true {. Vì case đúng đầu tiên thắng, thứ tự là quan trọng: chỉ khi bmi < 18.5 sai thì mới đến bmi < 25, nên mỗi case có thể coi như các case phía trên đã không khớp.
Switch có câu lệnh khởi tạo
Giống if, một switch có thể bắt đầu bằng một câu lệnh ngắn. Biến khai báo ở đó chỉ có phạm vi trong switch:
Câu lệnh khởi tạo cũng kết hợp được với switch không có biểu thức: switch n := len(items); { case n == 0: ... }.
fallthrough
Khi bạn thật sự muốn chạy tiếp vào case sau, hãy viết fallthrough ở câu lệnh cuối của case. Nó chuyển quyền điều khiển sang thân của case tiếp theo mà không tính điều kiện của case đó:
Cấp 2 in ra write rồi read, cộng dồn quyền theo chiều đi xuống. Điều kiện của các case phía sau không được kiểm tra: sau fallthrough từ case 2, case 1 vẫn chạy dù level là 2.
Quy tắc của fallthrough:
- Nó phải là câu lệnh cuối cùng trong case.
- Nó không được nằm trong case cuối cùng:
cannot fallthrough final case in switch. - Nó không được dùng trong type switch.
Trên thực tế fallthrough hiếm gặp trong code Go. Nhiều giá trị trong một case đã đáp ứng nhu cầu phổ biến, và gọi hàm tường minh thường rõ ràng hơn một chuỗi fallthrough.
break trong switch
break bên trong một case sẽ thoát khỏi switch. Các case tự kết thúc, nên bạn chỉ cần nó khi muốn rời case sớm. Cái bẫy nằm ở switch bên trong vòng lặp:
Không có nhãn loop, break chỉ kết thúc switch và vòng lặp tiếp tục chạy tới "c". Ngược lại, continue luôn tác động lên vòng lặp bao quanh, vì switch không phải vòng lặp.
Switch theo kiểu
Type switch rẽ nhánh theo kiểu động của một giá trị interface, dùng dạng đặc biệt v.(type):
Trong case chỉ có một kiểu, x mang đúng kiểu đó (len(x) dùng được trong case string). Trong case liệt kê nhiều kiểu, x giữ nguyên kiểu interface. Trang về type assertion giải thích chi tiết type switch và phép khẳng định v.(T).
Những điểm switch của Go làm khác
| Hành vi | C, Java, JavaScript | Go |
|---|---|---|
| Rơi xuống case tiếp theo | mặc định | chỉ khi có fallthrough |
break ở cuối mỗi case | bắt buộc | không cần |
| Nhiều giá trị trong một case | xếp chồng các case rỗng | case a, b, c: |
| Giá trị của case | hằng số (phần lớn) | biểu thức bất kỳ, tính từ trên xuống |
| Giá trị của switch | kiểu số nguyên (C) | kiểu bất kỳ so sánh được |
| Không có biểu thức switch | không cho phép | switch { case cond: } |
Biểu thức của case không bắt buộc là hằng số. case limit(), max + 1: là hợp lệ; chúng được tính lần lượt cho đến khi một biểu thức khớp, nên các biểu thức phía sau có thể không bao giờ chạy.
Tính đầy đủ
Go không kiểm tra xem một switch trên enum đã bao quát mọi giá trị hay chưa. Hãy thêm một default ghi log, trả về lỗi hoặc panic với những giá trị bạn không lường trước, hoặc dùng linter exhaustive (một phần của golangci-lint) để các case còn thiếu được báo ngay lúc build.
Câu hỏi thường gặp
switch trong Go có rơi xuống case tiếp theo không?
Không. Một case trong Go tự kết thúc khi gặp case tiếp theo; bạn không bao giờ phải viết break để dừng nó. Nếu muốn chương trình chạy tiếp vào thân của case sau, hãy viết fallthrough ở câu lệnh cuối của case. Nó nhảy vô điều kiện, không kiểm tra điều kiện của case sau.
Làm sao khớp nhiều giá trị trong một case trong Go?
Liệt kê chúng cách nhau bằng dấu phẩy: case "sat", "sun":. Case sẽ chạy nếu giá trị của switch bằng bất kỳ giá trị nào trong đó. Cách này thay cho việc xếp chồng các case rỗng như trong C hay Java.
switch không có điều kiện trong Go là gì?
switch { case x < 0: ...; case x == 0: ...; default: ... }. Khi không có biểu thức sau switch, mỗi case là một điều kiện boolean và case đúng đầu tiên sẽ chạy. Đây là cách viết chuẩn để thay một chuỗi if/else if dài.
break làm gì bên trong switch trong Go?
Nó kết thúc switch, không phải vòng lặp for bao quanh. Hiếm khi cần đến nó, vì các case tự kết thúc, nhưng nó hay làm bất ngờ những ai viết break trong một switch nằm trong vòng lặp và mong thoát khỏi vòng lặp. Để làm việc đó, hãy dùng break có nhãn hoặc return.