Lựa chọn Switch
Toán tử switch
cung cấp khả năng chọn một trong nhiều tùy chọn thuật toán. Theo quy tắc, số lượng tùy chọn thường lớn hơn hai, vì nếu không, việc sử dụng câu lệnh if/else
sẽ đơn giản hơn. Về lý thuyết, chuỗi các câu lệnh if/else
cho phép thay thế tương đương cho switch
trong nhiều trường hợp (nhưng không phải tất cả). Một đặc điểm quan trọng của switch
là tất cả các tùy chọn được chọn (xác định) dựa trên giá trị của biểu thức số nguyên, thường là một biến.
Trong trường hợp tổng quát, câu lệnh switch
trông như sau:
switch (expression)
{
case constant-expression : statements [break; ]
...
[ default : statements ]
}
2
3
4
5
6
Tiêu đề câu lệnh bắt đầu bằng từ khóa switch
. Nó phải được theo sau bởi một biểu thức trong dấu ngoặc đơn. Khối với dấu ngoặc nhọn cũng là bắt buộc.
Các giá trị số nguyên có thể thu được bằng cách đánh giá biểu thức nên được chỉ định dưới dạng hằng số sau từ khóa case
. Hằng số là một giá trị chữ của bất kỳ kiểu số nguyên nào, ví dụ, int
(10, 123), ushort
(các ký tự A
, s
, *
, v.v.), hoặc các phần tử của enum. Số thực, biến hoặc biểu thức không được phép sử dụng ở đây.
Có thể có nhiều tùy chọn case
như vậy, hoặc cũng có thể không có, điều này được biểu thị bằng dấu ngoặc tròn với chỉ số opt(n)
. Tất cả các biến thể phải có hằng số duy nhất (không được lặp lại).
Đối với mỗi lựa chọn được khai báo bằng case
, một câu lệnh phải được viết sau dấu hai chấm, câu lệnh này sẽ được thực thi nếu giá trị của biểu thức bằng với hằng số tương ứng. Một lần nữa, câu lệnh có thể là đơn giản hoặc phức hợp. Ngoài ra, có thể viết nhiều câu lệnh đơn giản mà không cần bao bọc chúng trong dấu ngoặc nhọn: chúng vẫn sẽ được thực thi như một nhóm (câu lệnh phức hợp).
Một hoặc nhiều câu lệnh này có thể được theo sau bởi câu lệnh nhảy break
.
Nếu có break
, sau khi thực thi các câu lệnh trước đó từ nhánh case
, câu lệnh switch
sẽ thoát, tức là quyền điều khiển được chuyển đến các câu lệnh bên dưới switch
.
Nếu không có break
, các câu lệnh của nhánh tiếp theo hoặc nhiều nhánh case
sẽ tiếp tục được thực thi, tức là cho đến khi gặp break
đầu tiên hoặc kết thúc khối switch
. Đây được gọi là "fall-through" (rơi xuyên).
Do đó, câu lệnh switch
không chỉ cho phép chia luồng thực thi thuật toán thành nhiều lựa chọn mà còn kết hợp chúng, điều mà toán tử if
không thể làm được. Mặt khác, trong câu lệnh switch
, không giống như if
, bạn không thể chọn một phạm vi giá trị làm điều kiện để kích hoạt các lựa chọn.
Từ khóa default
cho phép thiết lập biến thể thuật toán mặc định, tức là cho bất kỳ giá trị biểu thức nào khác ngoài các hằng số từ tất cả các cases
. Tùy chọn default
có thể không tồn tại, hoặc chỉ được phép có một.
Thứ tự liệt kê các hằng số case
và default
có thể là bất kỳ.
Ngay cả khi chưa có thuật toán cho nhánh default
, nên để nó rõ ràng là trống, tức là chứa break
. Một default
trống sẽ nhắc nhở bạn và các lập trình viên khác rằng có các tùy chọn khác tồn tại nhưng được coi là không quan trọng, vì nếu không, nhánh default
sẽ phải báo hiệu một lỗi.
Nhiều biến thể case
với các hằng số khác nhau có thể được liệt kê liên tiếp (hoặc từ trái sang phải) mà không có câu lệnh, nhưng cái cuối cùng phải có câu lệnh. Các cases
kết hợp như vậy được biểu thị trên sơ đồ bằng chỉ số (i)
.
Đây là câu lệnh switch
đơn giản nhất và vô dụng nhất:
switch(0)
{
}
2
3
Hãy xem xét một ví dụ phức tạp hơn với các chế độ khác nhau (StmtSelectionSwitch.mq5
). Trong đó, toán tử switch
được đặt bên trong vòng lặp để cho thấy cách hoạt động của nó phụ thuộc vào giá trị của biến điều khiển i
.
for(int i = 0; i < 7; i++)
{
double factor = 1.0;
switch(i)
{
case -1:
Print("-1: Never hit");
break;
case 1:
Print("Case 1");
factor = 1.5;
break;
case 2: // fall-through, không có break (!)
Print("Case 2");
factor *= 2;
case 3: // cùng câu lệnh cho 3 và 4
case 4:
Print("Case 3 & 4");
{
double local_var = i * i;
factor *= local_var;
}
break;
case 5:
Print("Case 5");
factor = 100;
break;
default:
Print("Default: ", i);
}
Print(factor);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Tùy chọn -1 sẽ không bao giờ đạt được vì vòng lặp thay đổi biến i
từ 0 đến 6 (bao gồm cả 6). Khi i
là 0, nhánh default
sẽ được kích hoạt. Nó cũng sẽ nhận quyền điều khiển khi i
bằng 6. Tất cả các giá trị i
có thể khác được phân phối theo các chỉ thị case
tương ứng. Đồng thời, không có câu lệnh break
sau case 2
, và do đó mã cho các tùy chọn 3 và 4 sẽ được thực thi ngoài 2 (trong những trường hợp như vậy, luôn khuyến nghị để lại một bình luận rằng điều này được thực hiện có chủ ý).
Các case 3
và 4
có một khối câu lệnh chung. Nhưng cũng cần lưu ý ở đây rằng nếu bạn muốn khai báo một biến cục bộ bên trong một trong các tùy chọn case
, bạn cần bao bọc các câu lệnh trong một khối phức hợp lồng nhau ({...}
). Ở đây, biến local_var
được định nghĩa theo cách này.
Nên lưu ý rằng trong trường hợp default
, không có câu lệnh break
. Điều này là không cần thiết vì default
được viết cuối cùng trong trường hợp này. Tuy nhiên, nhiều lập trình viên khuyên nên chèn break
vào cuối bất kỳ tùy chọn nào, ngay cả tùy chọn cuối cùng, vì nó có thể không còn là cuối cùng trong quá trình sửa đổi mã tiếp theo, và khi đó dễ quên thêm break
, điều này có thể dẫn đến lỗi trong logic chương trình.
Nếu trong switch
không có default
, và biểu thức tiêu đề không khớp với bất kỳ hằng số case
nào, toàn bộ switch
sẽ bị bỏ qua.
Kết quả của việc thực thi script, chúng ta sẽ nhận được các thông báo sau trong nhật ký:
Default: 0
1.0
Case 1
1.5
Case 2
Case 3 & 4
8.0
Case 3 & 4
9.0
Case 3 & 4
16.0
Case 5
100.0
Default: 6
1.0
2
3
4
5
6
7
8
9
10
11
12
13
14
15