Go Interface: Constrcut
Chúng ta đã xem qua mã nguồn của iface
và eface
và hiểu rằng iface
quan trọng nhất là itab
và _type
.
Để tìm hiểu rõ hơn về cách xây dựng giao diện, tiếp theo tôi sẽ sử dụng vũ khí của hợp ngữ để khám phá sự thật đằng sau.
Hãy xem một ví dụ mã nguồn:
Chạy lệnh:
Ta được mã hợp ngữ của hàm main như sau:
Chúng ta bắt đầu từ dòng 10, nếu không hiểu các dòng mã hợp ngữ trước đó, bạn có thể quay lại xem hai bài viết trước trên tài khoản công khai, ở đây tôi sẽ bỏ qua.
Dòng mã hợp ngữ | Mô tả |
---|---|
10-14 | Xây dựng các tham số cho cuộc gọi runtime.convT2I64(SB) |
Chúng ta hãy xem hàm này có dạng tham số như thế nào:
convT2I64
sẽ xây dựng một interface
, cụ thể là giao diện Person
của chúng ta.
Tham số đầu tiên được đặt tại vị trí (SP)
, ở đây nó được gán địa chỉ của go.itab."".Student,"".Person(SB)
.
Chúng ta tìm thấy nó trong mã hợp ngữ được tạo ra:
Kích thước của nó là 40 byte, để nhớ lại:
Tổng cộng các trường kích thước lại, kích thước của cấu trúc itab
là 40 byte. Chuỗi số trên thực tế là nội dung đã được tuần tự hóa của itab
, lưu ý rằng hầu hết các số là 0, từ 24 byte trở đi, 4 byte da 9f 20 d4
thực tế là giá trị hash
của itab
, được sử dụng để kiểm tra xem hai kiểu có giống nhau không.
Hai dòng tiếp theo là các chỉ thị liên kết, đơn giản là kết hợp tất cả các tệp nguồn lại với nhau, gán một vị trí toàn cầu cho mỗi biểu tượng. Ý nghĩa ở đây cũng khá rõ ràng: 8 byte đầu tiên cuối cùng lưu trữ địa chỉ của type."".Person
, tương ứng với trường inter
trong itab
, đại diện cho kiểu giao diện; 8-16 byte cuối cùng cuối cùng lưu trữ địa chỉ của type."".Student
, tương ứng với trường _type
trong itab
, đại diện cho kiểu cụ thể.
Tham số thứ hai đơn giản hơn, nó là địa chỉ của số 18
, điều này cũng được sử dụng khi khởi tạo cấu trúc Student
.
Dòng mã hợp ngữ | Hoạt động |
---|---|
15 | Gọi runtime.convT2I64(SB) |
Chúng ta sẽ xem đoạn mã sau:
Đoạn mã này khá đơn giản, nó gán tab
cho trường tab
của iface
; phần data
được cấp phát một khối bộ nhớ trên heap, sau đó sao chép giá trị 18
từ elem
vào đó. Như vậy, iface
đã được xây dựng.
Dòng mã hợp ngữ | Mô tả |
---|---|
17 | Gán i.tab cho CX |
18 | Gán i.data cho AX |
19-21 | Kiểm tra xem i.tab có phải là nil hay không, nếu không phải, di chuyển CX 8 byte, tức là gán trường _type của itab cho CX , đây là kiểu cụ thể của giao diện, cuối cùng sẽ được sử dụng làm đối số cho hàm fmt.Println |
Sau đó, là cuộc gọi hàm fmt.Println
và công việc chuẩn bị tham số trước đó, không cần nói thêm.
Như vậy, chúng ta đã hoàn thành quá trình xây dựng một interface
.
【Mở rộng 1】
Làm thế nào để in ra giá trị hash
của kiểu giao diện?
Ở đây, tôi tham khảo một bài viết được dịch bởi Cao Đại Thần, bạn có thể tham khảo trong tài liệu tham khảo. Cách làm cụ thể như sau:
Chúng ta đã định nghĩa một phiên bản “giả mạo” của iface
và itab
, tôi gọi nó là “giả mạo” vì một số cấu trúc dữ liệu quan trọng trong itab
đã không được mở rộng, ví dụ như _type
, so sánh với định nghĩa chính thức sẽ thấy điều này, nhưng phiên bản “giả mạo” vẫn hoạt động, vì _type
chỉ là một con trỏ.
Trong hàm main
, trước tiên chúng ta xây dựng một đối tượng giao diện qcrao
, sau đó chuyển đổi kiểu ép buộc và cuối cùng đọc giá trị hash
, rất tuyệt vời! Bạn cũng có thể thử làm điều này.
Kết quả chạy:
Đáng lưu ý là khi xây dựng giao diện qcrao
, ngay cả khi tôi thay đổi giá trị age
thành giá trị khác, giá trị hash
vẫn không thay đổi, điều này có thể dự đoán được, giá trị hash
chỉ phụ thuộc vào các trường và phương thức của nó.