- vừa được xem lúc

[Procedural Programming + Ada] Bài 8 - Record Defaults & Access Pointers

0 0 18

Người đăng: Semi Dev

Theo Viblo Asia

Mặc dù việc thiết lập giá trị mặc định cho các trường dữ liệu khi khởi tạo record được Ada hỗ trợ ở cấp độ cú pháp của ngôn ngữ. Tuy nhiên ở bài viết giới thiệu về record trước đó, mình đã tránh đề cập tới để duy trì định nghĩa record đơn giản và tập trung vào các yếu tố định kiểu dữ liệu. Và bây giờ đã là thời điểm phù hợp để chúng ta có thể tìm hiểu nhiều hơn về record trong Ada.

Record Defaults

Để thiết lập giá trị mặc định cho các trường dữ liệu của record, thao tác cần thực hiện chỉ đơn giản là gắn thêm một phép gán vào sau các yếu tố định kiểu dữ liệu giống với các ngôn ngữ như TypeScript hay Kotlin.

with Ada.Text_IO; use Ada.Text_IO; procedure Main is type Date is record Day : Integer range 1 .. 31 := 1; Month : Integer range 1 .. 12 := 1; Year : Integer range 1 .. 3000 := 1900; end record; Birthday : Date;
begin Put_Line ("Birthday : record Date"); Put_Line (" Day => " & Integer'Image (Birthday.Day)); Put_Line (" Month => " & Integer'Image (Birthday.Month)); Put_Line (" Year => " & Integer'Image (Birthday.Year));
end Main;

Và thực tế thì tất cả các biến được khai báo ở bất kỳ vị trí nào, bao gồm các tham số của các sub-program và các biến cục bộ cũng đều có thể được gắn giá trị mặc định với thao tác tương tự (nếu cần thiết).

Birthday : record Date Day => 1 Month => 1 Year => 1900

Discriminant

Các record cũng có thể được định nghĩa kèm theo discriminant. Điều này cũng rất cần thiết nếu như chúng ta đang thiết kế record có chứa các array và muốn để cho code sử dụng bên ngoài quyết định độ rộng của array bên trong record ở thời điểm định kiểu dữ liệu cho biến lưu trữ.

subtype Positive_Integer is Integer range 1 .. Integer'Last;
type Item_List (size : Positive_Integer) is record Name : String; List : array (1 .. size) of String;
end record;

Ngoài ra thì các yếu tố discriminant còn được sử dụng để định nghĩa variant record - tạm hiểu là kiểu record có cấu trúc thay đổi tùy thuộc vào yếu tố discriminiant được cung cấp ở thời điểm định kiểu cho một biến nào đó. Các variant record của Ada được so sánh tương đương với union trong C hay C++ và các kiểu dữ liệu gộp sum type trong các ngôn ngữ FP như Elm hay Haskell.

Tuy nhiên vì một vài lý do chủ quan về mặt cú pháp ngôn ngữ, mình sẽ không sử dụng các variant record trong suốt Sub-Series này và chỉ trích dẫn liên kết tham khảo ở đây nếu bạn quan tâm learn.adacore.com > Variant Records.

Access Pointers

Các biến con trỏ pointer trong C hay C++ là các công cụ lập trình rất mạnh mẽ. Tuy nhiên, với góc nhìn đứng từ môi trường ứng dụng và triết lý thiết kế của Ada thì đây lại là những cấu trúc thiếu an toàn. Chính vì vậy nên Ada đã cung cấp những công cụ thay thế như các chỉ dẫn inout cho các tham số của các sub-program, và một khái niệm biến tham chiếu có tên là access.

Mặc dù được Ada gọi là kiểu con trỏ nhưng các biến access không có ý nghĩa về mặt cấu trúc giống như các pointer trong C hay C++, mà thực ra các con trỏ access chỉ mang tính chất danh nghĩa và cung cấp thêm một cú pháp sử dụng thay thế cho kiểu dữ liệu ban đầu.

with Ada.Text_IO; use Ada.Text_IO; procedure Main is type Item; -- early declaration type Item_Access is access Item; -- detail definition type Item is record Value: Integer; Next_Access: Item_Access; end record; -- declare a list Integer_List_Access: Item_Access; -- declare a cursor Current_Access: Item_Access;
begin Integer_List_Access := new Item'( Value => 0, Next_Access => null ); Current_Access := Integer_List_Access; -- add new item Current_Access.Next_Access := new Item'( Value => 1, Next_Access => null ); Current_Access := Current_Access.Next_Access; -- add new item Current_Access.Next_Access := new Item'( Value => 2, Next_Access => null ); Current_Access := Current_Access.Next_Access; -- move cursor to first item and print list Current_Access := Integer_List_Access; loop Put_Line ( "Item Value : " & Integer'Image (Current_Access.Value)); exit when Current_Access.Next_Access = null; Current_Access := Current_Access.Next_Access; end loop;
end Main;
Item Value : 0
Item Value : 1
Item Value : 2

Trong code ví dụ này thì chúng ta đang định nghĩa Integer_List là một danh sách xuất phát từ một Item nối tiếp tới một Item tiếp theo, và cứ thế cho tới vô cùng. Chúng ta sẽ không thể định nghĩa trường Next trỏ tới chính kiểu Item đang định nghĩa, tuy nhiên lại có thể tạo ra một kiểu con trỏ access gián tiếp trỏ tới Item để sử dụng ở đây.

Tất cả các thao thực hiện thông qua các con trỏ access đều có cú pháp giống với khi thao tác qua các biến thông thường, ngoại trừ thao tác khởi tạo giá trị lưu trữ sẽ yêu cầu sử dụng phép thực thi new, và thao tác truy xuất tổng bộ record từ con trỏ access sẽ được thực hiện thông qua trường Record_Access.all để có thể gán sang một biến khác thuộc kiểu dữ liệu ban đầu.

Và ở đây chúng ta có giá trị null được Ada chỉ sử dụng duy nhất cho các con trỏ access để mô tả trạng thái vô định, chưa trỏ tới một đối tượng dữ liệu nào. Còn ngoài ra thì như đã nói trước đó là Ada không hỗ trợ việc sử dụng giá trị null cho các kiểu dữ liệu khác. Khi xây dựng các package cung cấp các công cụ làm việc với một kiểu dữ liệu nào đó, chúng ta sẽ phải tự định nghĩa trường hợp giá trị vô nghĩa với logic hoạt động của các sub-program nếu cần thiết.

Oh, và chúng ta lại được biết thêm là các kiểu dữ liệu có thể được khai báo ngắn gọn declaration ở phía trên và sau đó định nghĩa chi tiết definition có thể được viết vào một thời điểm sau đó. Bằng cách này thì chúng ta sẽ có thể sử dụng tên của một kiểu dữ liệu được khai báo tạm thời cho các định nghĩa kiểu dữ liệu khác có liên quan liên quan - trước khi viết định nghĩa cụ thể cho kiểu ban đầu.

Vẫn còn rất nhiều thứ đề nói về record và chúng ta sẽ tiếp tục tìm hiểu thêm ở những bài viết tiếp theo.

(chưa đăng tải) [Procedural Programming + Ada] Bài 9 - Record Primitives & Encapsulation

Bình luận

Bài viết tương tự

- vừa được xem lúc

Closure trong Javascript - Phần 2: Định nghĩa và cách dùng

Các bạn có thể đọc qua phần 1 ở đây. Để mọi người không quên, mình xin tóm tắt gọn lại khái niệm lexical environment:.

0 0 67

- vừa được xem lúc

Var vs let vs const? Các cách khai báo biến và hằng trong Javascript

Dạo này mình tập tành học Javascript, thấy có 2 cách khai báo biến khác nhau nên đã tìm tòi sự khác biệt. Nay xin đăng lên đây để mọi người đọc xong hy vọng phân biệt được giữa let và var, và sau đó là khai báo hằng bằng const.

0 0 47

- vừa được xem lúc

VueJS: Tính năng Mixins

Chào mọi người, hôm nay mình sẽ viết về Mixins và 1 số vấn đề trong sử dụng Mixins hay ho mà mình gặp trong dự án thực. Trích dẫn từ trang chủ của VueJS:.

0 0 41

- vừa được xem lúc

Asset Pipeline là cái chi chi?

Asset Pipeline. Asset pipeline là cái chi chi. . Giải thích:.

0 0 75

- vừa được xem lúc

Tạo data table web app lấy dữ liệu từ Google Sheets sử dụng Apps Script

Google Sheets là công cụ tuyệt vời để lưu trữ bảng tính trực tuyến, bạn có thể truy cập bảng tính bất kỳ lúc nào ở bất kỳ đâu và luôn sẵn sàng để chia sẻ với người khác. Bài này gồm 2 phần.

0 0 280

- vừa được xem lúc

Học Deep Learning trên Coursera miễn phí

Bạn muốn bắt đầu với Deep Learning nhưng không biết bắt đầu từ đâu? Bạn muốn có một công việc ở mức fresher về Deep Learning? Bạn muốn khoe bạn bè về kiến thức Deep Learning của mình. Bắt đầu từ đâu.

0 0 50