Trong bất kỳ môi trường lập trình nào thì cũng có những trường hợp ứng dụng nhất định mà chúng ta sẽ cần phải định nghĩa một cấu trúc Đệ Quy – tức là trong code định nghĩa đang viết có sử dụng ngay tên của chính kiểu dữ liệu đó. Và ở đây chúng ta sẽ tìm hiểu về thao tác định nghĩa một cấu trúc như vậy trong Ada
.
Recursive Record
Trong môi trường của C
như đã biết – khi viết định nghĩa struct
, chúng ta có thể sử dụng ngay tên của kiểu struct
đang định nghĩa để định kiểu cho các trường dữ liệu bên trong nếu cần thiết. Tuy nhiên thông thường thì khi làm việc với các struct
chúng ta sẽ sử dụng định kiểu dạng con trỏ pointer
và như vậy một struct
đệ quy thường có dạng như thế này:
typedefstructnode{void* data;structnode* next;} node_struct;
Và ở đây trong Ada
, để định nghĩa một record
đệ quy thì chúng ta cũng có thể sử dụng dạng thức tương tự với sự hỗ trợ của khái niệm con trỏ access
.
package Item is
type Struct; -- early declaration
type Pointer is access all Struct;
type Struct is record
Value: Integer;
Next: Pointer;
end record;
private
-- nothing here
end Item;
Khi sử dụng kiểu con trỏ access
để làm tên định kiểu chính cho record
giống như khi code C
, chúng ta sẽ phải sử dụng khởi tạo với cú pháp new
vay mượn từ nhóm công cụ Lập Trình Hướng Đối Tượng Object-Oriented Programming
. Cú pháp này sẽ tách lấy địa chỉ tham chiếu của record
để trả về cho biến access
lưu lại.
with Ada.Text_IO; use Ada.Text_IO;
with Item; use Item;
procedure Main is
Instance, Cursor : Item.Pointer;
begin
Instance := new Item.Struct'(0, null);
Instance := new Item.Struct'(1, Instance);
Instance := new Item.Struct'(2, Instance);
Instance := new Item.Struct'(3, Instance);
Instance := new Item.Struct'(4, Instance);
Instance := new Item.Struct'(5, Instance);
Instance := new Item.Struct'(6, Instance);
Instance := new Item.Struct'(7, Instance);
Instance := new Item.Struct'(8, Instance);
Instance := new Item.Struct'(9, Instance);
-- move cursor from the first item and print the list
Cursor := Instance;
Put ("List : ");
while Cursor /= null loop
Put (Integer'Image (Cursor.Value) & " ");
Cursor := Cursor.Next;
end loop;
end Main;
List : 9 8 7 6 5 4 3 2 1 0
Dereference Access
Trong những trường hợp nhất định khi làm việc với các kiểu cấu trúc khác – không phải là mảng array
hoặc record
– thì chúng ta sẽ phải thực hiện thao tác chuyển kiểu trong code. Thao tác truy xuất tổng bộ nội dung của một access
và gán trả về một biến thuộc kiểu dữ liệu nguyên bản được gọi là dereference
và được thực hiện thông qua khóa all
của con trỏ access
như sau:
Pointer : Item_Access := new Item'( Value => 1, Next_Access => null );
Origin : Item := Pointer.all;
Ở chiều ngược lại, khi chúng ta muốn tách lấy địa chỉ từ một biến thông thường lưu trữ array
hoặc record
để gán vào một biến con trỏ access
thì chúng ta cần đảm bảo các điều kiện là:
- Phải tạo một biến cục bộ
local
củasub-program
được khai báo với từ khóaaliased
ở phía trước tên định kiểu. - Biến con trỏ
access
cũng phải được khai báo cục bộ trong phạm vi củasub-program
.
Các điều kiện này là để đảm bảo rằng, thao tác chuyển kiểu từ giá trị Value
sang kiểu địa chỉ Access
cần được kiểm soát trong phạm vi cục bộ của từng sub-program
. Đây là một dạng thiết kế an toàn mà Ada
tạo ra để đảm bảo việc sử dụng kiến trúc con trỏ access
phải được kiểm soát chặt chẽ trong logic nội tại của người viết code.
Sau đó thao tác tách lấy địa chỉ tham chiếu và gán vào biến con trỏ access
sẽ có thể thực hiện được nhờ thuộc tính Value'Access
.
Value : aliased Item;
Pointer : Item_Access;
Pointer := Value'Access;
Mặc dù vẫn còn rất nhiều thứ để nói về record
trong Ada
tuy nhiên chúng ta sẽ để dành cho một Sub-Series khác nói về tư duy Lập Trình Hướng Đối Tượng. Ở đây chúng ta sẽ chuyển sang tìm hiểu những công cụ phổ biến khác mà Ada
cung cấp cho môi trường lập trình phổ thông (không bao gồm lớp lập trình nhúng embedded programming
).
[Procedural Programming + Ada] Bài 10 – Overloading Sub-program & Generics
Nguồn: viblo.asia