[Procedural Programming + Ada] Bài 9 – Recursive Record & Access Pointer

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

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ủa sub-program được khai báo với từ khóa aliased ở 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ủa sub-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

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ