Bối cảnh, phạm vi và thời gian tồn tại của các biến
MQL5 thuộc về ngôn ngữ lập trình sử dụng dấu ngoặc nhọn để nhóm các câu lệnh thành các khối mã.
Hãy nhớ rằng một chương trình bao gồm các khối lệnh và một khối lệnh phải tồn tại chắc chắn. Trong các mẫu tập lệnh từ Phần 1, chúng ta đã thấy hàm OnStart
. Phần thân của hàm này (văn bản được bao quanh bởi dấu ngoặc nhọn theo sau tên hàm) chính xác là một khối mã cần thiết như vậy.
Bên trong mỗi khối, ngữ cảnh cục bộ được hình thành, tức là một vùng giới hạn khả năng hiển thị và thời gian tồn tại của các biến được mô tả bên trong nó. Cho đến nay, chúng ta chỉ gặp các ví dụ trong đó dấu ngoặc nhọn định nghĩa thân hàm. Tuy nhiên, chúng cũng có thể được sử dụng để tạo thành các toán tử ghép, trong cú pháp mô tả các lớp và không gian tên. Tất cả các phương pháp này cũng định nghĩa các vùng khả năng hiển thị và sẽ được xem xét trong các phần có liên quan. Ở giai đoạn này, chúng ta chỉ xem xét một loại khối cục bộ, cụ thể là các khối bên trong hàm.
Cùng với các vùng cục bộ, mỗi chương trình cũng có một ngữ cảnh toàn cục, tức là một vùng có các định nghĩa về biến, hàm và các thực thể khác được tạo ra ngoài các khối khác.
Về phía tập lệnh đơn giản, trong đó MQL Wizard đã tạo ra hàm rỗng OnStart
duy nhất, thì sẽ chỉ có 2 vùng trong đó: Một vùng toàn cục và một vùng cục bộ (bên trong thân hàm OnStart
, mặc dù nó trống). Tập lệnh bên dưới minh họa điều này bằng các bình luận.
// PHẠM VI TOÀN CỤC
void OnStart () {
// PHẠM VI CỤ THỂ "OnStart"
} // PHẠM VI TOÀN CỤC
2
3
4
Xin lưu ý rằng vùng toàn cục trải dài khắp mọi nơi ngoại trừ hàm OnStart
(cả trước và sau hàm này). Về cơ bản, nó bao gồm mọi thứ ngoài bất kỳ hàm nào (nếu có nhiều hàm), nhưng không có gì trong tập lệnh này, ngoại trừ OnStart
.
Chúng ta có thể mô tả các biến như i, j, k
ở đầu tệp và chúng sẽ trở thành biến toàn cục.
// PHẠM VI TOÀN CỤC
int i, j, k;
void OnStart () {
// PHẠM VI CỤC BỘ "OnStart"
} // PHẠM VI TOÀN CỤC
2
3
4
5
INFO
Biến toàn cục được tạo ngay khi khởi động chương trình MQL trong thiết bị đầu cuối và tồn tại trong toàn bộ thời gian thực thi chương trình.
INFO
Người lập trình có thể ghi lại và đọc nội dung của các biến toàn cục từ bất kỳ vị trí nào trong chương trình.
Về cơ bản, nên mô tả các biến toàn cục ngay ở đầu, nhưng điều này là cần thiết. Nếu chúng ta di chuyển khai báo xuống dưới toàn bộ hàm OnStart
, về cơ bản sẽ không có gì thay đổi. Chỉ là các lập trình viên khác sẽ khó có thể hiểu ngay được mã có biến, định nghĩa của biến mà người ta vẫn chưa có.
Điều thú vị là bản thân hàm OnStart
cũng được khai báo trong ngữ cảnh toàn cục. Nếu chúng ta thêm một hàm khác, nó cũng sẽ được khai báo trong ngữ cảnh toàn cục. Hãy nhớ lại cách chúng ta tạo hàm Greeting
trong Phần 1 và gọi nó từ hàm OnStart
. Đây là hiệu ứng của tên hàm và phương thức tham chiếu đến nó (cách thực thi nó) được biết đến trong toàn bộ mã nguồn. Không gian tên thêm một số tính năng hay vào đó; tuy nhiên, chúng ta sẽ tìm hiểu về chúng sau.
Mỗi hàm có một vùng cục bộ chỉ thuộc về hàm đó: Một vùng cục bộ nằm bên trong OnStart
và một vùng khác nằm bên trong Greeting
, đây là vùng riêng của hàm đó và khác với cả vùng cục bộ của OnStart
và vùng toàn cục.
Các biến được mô tả trong thân hàm được gọi là cục bộ. Chúng được tạo theo mô tả của chúng khi gọi hàm có liên quan trong quá trình thực thi chương trình. Biến cục bộ chỉ có thể được sử dụng bên trong khối chứa chúng. Chúng không thể nhìn thấy hoặc truy cập được từ bên ngoài. Khi rời khỏi hàm, các biến cục bộ sẽ bị hủy.
Ví dụ mô tả các biến cục bộ x, y, z bên trong hàm OnStart
:
// PHẠM VI TOÀN CẦU
int i, j, k;
void OnStart () {
// PHẠM VI CỤ THỂ "OnStart"
int x, y, z;
} // PHẠM VI TOÀN CẦU
2
3
4
5
6
Cần lưu ý rằng cặp dấu ngoặc nhọn có thể được sử dụng để mô tả hàm và các câu lệnh khác cũng như để tạo thành khối mã bên trong. Việc lồng đơn vị là không giới hạn.
Các khối lồng nhau thường được thêm vào để giảm thiểu phạm vi của các biến được sử dụng trong một vị trí mã nhỏ được cô lập về mặt logic (nếu nó không được đặt bởi một hàm vì lý do này hay lý do khác). Điều này cho phép giảm khả năng sửa đổi sai biến khi nó không được cung cấp hoặc một số tác dụng phụ không mong muốn do nỗ lực tái sử dụng cùng một biến cho các nhu cầu khác nhau (đây không phải là một thực hành tốt).
Dưới đây là một hàm mẫu trong đó mức lồng nhau đơn vị là 2 (nếu chúng ta coi khối có thân hàm là mức đầu tiên) và 2 khối như vậy được tạo và sẽ được thực thi liên tiếp.
void OnStart () {
// PHẠM VI CỤ THỂ "OnStart"
int x , y , z ; {
// PHẠM VI CỤ THỂ 1
int p ; // ... sử dụng p cho nhiệm vụ 1
}
{
// PHẠM VI CỤ THỂ 2
// y = p; // lỗi: 'p' - định danh chưa khai báo
int p ; // từ bây giờ 'p' được khai báo
// ... sử dụng p cho nhiệm vụ 2
}
// p = x; // lỗi: 'p' - định danh chưa khai báo
}
2
3
4
5
6
7
8
9
10
11
12
13
14
Bên trong cả hai khối, biến p
được mô tả, được sử dụng cho nhiều mục đích khác nhau trong đó. Trên thực tế, đây là hai biến khác nhau, mặc dù có cùng tên hiển thị bên trong mỗi khối.
Nếu biến được đưa ra danh sách ban đầu của các biến cục bộ của hàm, nó có thể chứa một số giá trị còn lại khi thoát khỏi khối đầu tiên, do đó phá vỡ hoạt động của khối thứ hai. Hơn nữa, đôi khi lập trình viên có thể đưa p
vào thứ gì đó khác ngay từ đầu hàm, và sau đó các tác dụng phụ có thể xảy ra trong khối đầu tiên.
Ngoài một trong hai khối lồng nhau, biến p không được biết đến và do đó, nỗ lực tham chiếu đến biến này từ khối chung của hàm sẽ dẫn đến lỗi biên dịch ("mã định danh chưa được khai báo").
Cũng cần lưu ý rằng một biến có thể được mô tả không phải ở phần đầu của khối, mà ở giữa hoặc thậm chí gần cuối khối hơn. Khi đó, biến đó không được định nghĩa trong toàn bộ khối mà chỉ ở bên dưới định nghĩa của nó. Do đó, khi tham chiếu đến biến ở trên phần mô tả của nó, lỗi tương tự sẽ xảy ra.
Do đó, phạm vi vùng biến đổi có thể khác với ngữ cảnh (toàn bộ khối).
Cả hai phiên bản của bài toán đều được minh họa trong một ví dụ: Hãy thử đưa bất kỳ chuỗi nào vào các câu lệnh p = x
và y = p
và biên dịch mã nguồn.
Bộ nhớ được phân bổ cho tất cả các biến cục bộ của hàm ngay khi điều khiển được truyền vào bên trong hàm. Tuy nhiên, đây không phải là kết thúc của việc tạo ra chúng. Sau đó, chúng được khởi tạo (giá trị ban đầu được thiết lập), khởi tạo được định nghĩa rõ ràng bởi lập trình viên hoặc ngầm định bởi các giá trị mặc định của trình biên dịch. Đồng thời, ngữ cảnh là cốt lõi, trong đó các biến được mô tả.