Lựa chọn If
Câu lệnh if
có nhiều dạng. Trong trường hợp đơn giản nhất, nó thực thi câu lệnh phụ thuộc nếu điều kiện được chỉ định là đúng:
if (condition)
statement
2
Nếu điều kiện là sai (false
), câu lệnh sẽ bị bỏ qua và quá trình thực thi ngay lập tức chuyển sang phần còn lại của thuật toán (các câu lệnh tiếp theo, nếu có).
Câu lệnh có thể là đơn giản hoặc phức hợp. Điều kiện là một biểu thức thuộc kiểu boolean hoặc kiểu có thể ép buộc.
Dạng thứ hai cho phép bạn chỉ định hai nhánh hành động: không chỉ cho điều kiện đúng (statement_A
) mà còn cho điều kiện sai (statement_B
):
if (condition)
statement_A
else
statement_B
2
3
4
Dù câu lệnh được kiểm soát nào được thực thi, thuật toán sẽ tiếp tục thực hiện các câu lệnh bên dưới câu lệnh if/else
.
Ví dụ, một script có thể tuân theo một chiến lược khác nhau tùy thuộc vào khung thời gian của biểu đồ mà nó được đặt lên. Để làm điều này, chỉ cần phân tích giá trị trả về bởi hàm tích hợp sẵn Period
. Giá trị này thuộc kiểu enum ENUM_TIMEFRAMES. Nếu nó nhỏ hơn PERIOD_D1
, điều đó có nghĩa là giao dịch ngắn hạn, nếu không thì là giao dịch dài hạn (StmtSelectionIf.mq5
).
if(Period() < PERIOD_D1)
{
Print("Intraday");
}
else
{
Print("Interday");
}
2
3
4
5
6
7
8
Là một câu lệnh trong nhánh else
, có thể chỉ định toán tử if
tiếp theo, và do đó sắp xếp chúng thành một chuỗi các kiểm tra liên tiếp. Ví dụ, đoạn mã sau đếm số lượng chữ cái in hoa và ký hiệu dấu câu (chính xác hơn là các ký tự không phải chữ cái Latinh) trong một chuỗi.
string s = "Hello, " + Symbol();
int capital = 0, punctuation = 0;
for(int i = 0; i < StringLen(s); ++i)
{
if(s[i] >= `A` && s[i] <= `Z`)
++capital;
else if(!(s[i] >= `a` && s[i] <= `z`))
++punctuation;
}
Print(capital, " ", punctuation);
2
3
4
5
6
7
8
9
10
Vòng lặp được tổ chức qua tất cả các ký tự của chuỗi (đánh số bắt đầu từ 0) và hàm StringLen
trả về độ dài của chuỗi. Câu lệnh if
đầu tiên kiểm tra từng ký tự để xem nó có thuộc phạm vi từ A
đến Z
hay không và, nếu thành công, tăng bộ đếm capital
lên 1. Nếu ký tự không thuộc phạm vi này, câu lệnh if
thứ hai được chạy, trong đó điều kiện thuộc phạm vi chữ cái thường (s[i] >= 'a' && s[i] <= 'z'
) được đảo ngược với '!'. Nói cách khác, điều kiện có nghĩa là ký tự không nằm trong phạm vi đã cho. Với hai kiểm tra liên tiếp, nếu ký tự không phải là chữ cái in hoa (else
) và không phải là chữ cái thường (câu lệnh if
thứ hai), chúng ta có thể kết luận rằng ký tự không phải là chữ cái của bảng chữ cái Latinh. Trong trường hợp này, chúng ta tăng bộ đếm punctuation
.
Các kiểm tra tương tự có thể được viết dưới dạng chi tiết hơn, với các khối {...}
để rõ ràng.
int capital = 0, small = 0, punctuation = 0;
for(int i = 0; i < StringLen(s); ++i)
{
if(s[i] >= `A` && s[i] <= `Z`)
{
++capital;
}
else
{
if(s[i] >= `a` && s[i] <= `z`)
{
++small;
}
else
{
++punctuation;
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Việc sử dụng dấu ngoặc nhọn giúp tránh các lỗi logic có thể xảy ra khi lập trình viên chỉ dựa vào thụt đầu dòng trong mã. Đặc biệt, vấn đề phổ biến nhất được gọi là else
"treo".
Khi các câu lệnh if
được lồng nhau, đôi khi có ít nhánh else
hơn số lượng if
. Dưới đây là một ví dụ:
factor = 0.0;
if(mode > 10)
if(mode > 20)
factor = +1.0;
else
factor = -1.0;
2
3
4
5
6
Thụt đầu dòng cho biết ý định logic của lập trình viên: factor
nên trở thành +1 khi mode
lớn hơn 20, giữ nguyên bằng 0 khi mode
nằm trong khoảng từ 10 đến 20, và thay đổi thành -1 nếu không (mode <= 10
). Nhưng liệu mã có hoạt động theo cách đó không?
Trong MQL5, mỗi else
được giả định là liên quan đến câu lệnh if
gần nhất trước đó (mà không có else
). Kết quả là, trình biên dịch sẽ xử lý các câu lệnh như sau:
factor = 0.0;
if(mode > 10)
if(mode > 20)
factor = +1.0;
else
factor = -1.0;
2
3
4
5
6
Vì vậy, factor
sẽ là -1 trong phạm vi mode
từ 10 đến 20, và 0 cho mode <= 10
. Điều thú vị nhất là chương trình không tạo ra bất kỳ lỗi chính thức nào, cả trong quá trình biên dịch lẫn thực thi. Tuy nhiên, nó không hoạt động chính xác.
Để loại bỏ các vấn đề logic tinh vi như vậy, cần đặt dấu ngoặc nhọn.
if(mode > 10)
{
if(mode > 20)
factor = +1.0;
}
else
factor = -1.0;
2
3
4
5
6
7
Để giữ thiết kế nhất quán, nên sử dụng các khối trong tất cả các nhánh của câu lệnh nếu ít nhất một khối đã được yêu cầu trong đó.
Khi sử dụng vòng lặp để kiểm tra sự bằng nhau, hãy lưu ý đến khả năng xảy ra lỗi đánh máy khi một dấu =
được viết thay vì hai ký tự ==
. Điều này biến phép so sánh thành phép gán, và giá trị được gán sẽ được phân tích như một điều kiện logic. Ví dụ,
// lẽ ra phải là x == y + 1, điều này sẽ cho false và bỏ qua if
if(x = y + 1) // cảnh báo: biểu thức không phải boolean
{
// gán x = 5 và coi x là true, nên if được thực thi
}
2
3
4
5
Trình biên dịch sẽ tạo ra cảnh báo "expression not boolean".