Lua - Metatables

Khả năng đáp ứng là một bảng giúp sửa đổi hành vi của bảng mà nó được gắn vào với sự trợ giúp của tập khóa và các phương thức meta liên quan. Các phương thức meta này là chức năng Lua mạnh mẽ cho phép các tính năng như -

  • Thay đổi / thêm chức năng cho các toán tử trên bảng.

  • Tìm kiếm các dữ liệu có thể đo được khi khóa không có sẵn trong bảng bằng cách sử dụng __index trong metatable.

Có hai phương pháp quan trọng được sử dụng để xử lý các bảng đo lường bao gồm:

  • setmetatable(table,metatable) - Phương pháp này được sử dụng để thiết lập độ chính xác cho một bảng.

  • getmetatable(table) - Phương pháp này được sử dụng để lấy độ phân giải của một bảng.

Trước tiên, hãy xem cách đặt một bảng giống như một bảng khác. Nó được hiển thị bên dưới.

mytable = {}
mymetatable = {}
setmetatable(mytable,mymetatable)

Đoạn mã trên có thể được biểu diễn trong một dòng như hình dưới đây.

mytable = setmetatable({},{})

_mục lục

Dưới đây là một ví dụ đơn giản về việc tra cứu bảng meta khi nó không có sẵn trong bảng.

mytable = setmetatable({key1 = "value1"}, {
   __index = function(mytable, key)
	
      if key == "key2" then
         return "metatablevalue"
      else
         return mytable[key]
      end
   end
})

print(mytable.key1,mytable.key2)

Khi chúng ta chạy chương trình trên, chúng ta sẽ nhận được kết quả sau.

value1 metatablevalue

Hãy để chúng tôi giải thích những gì đã xảy ra trong ví dụ trên theo các bước.

  • Bảng mytable ở đây là {key1 = "value1"}.

  • Metatable được đặt cho mytable có chứa hàm cho __index, mà chúng tôi gọi là metamethod.

  • Metamethod thực hiện một công việc đơn giản là tìm kiếm một chỉ mục "key2", nếu nó được tìm thấy, nó sẽ trả về "metatablevalue", nếu không thì trả về giá trị của mytable cho chỉ mục tương ứng.

Chúng ta có thể có một phiên bản đơn giản của chương trình trên như hình dưới đây.

mytable = setmetatable({key1 = "value1"}, 
   { __index = { key2 = "metatablevalue" } })
print(mytable.key1,mytable.key2)

__newindex

Khi chúng ta thêm __newindex vào metatable, nếu các khóa không có sẵn trong bảng, thì hoạt động của các khóa mới sẽ được xác định bằng các phương thức meta. Dưới đây là một ví dụ đơn giản trong đó chỉ mục của metatable được đặt khi chỉ mục không có sẵn trong bảng chính.

mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })

print(mytable.key1)

mytable.newkey = "new value 2"
print(mytable.newkey,mymetatable.newkey)

mytable.key1 = "new  value 1"
print(mytable.key1,mymetatable.newkey1)

Khi bạn chạy chương trình trên, bạn nhận được kết quả sau.

value1
nil	new value 2
new  value 1	nil

Bạn có thể thấy trong chương trình trên, nếu một khóa tồn tại trong bảng chính, nó chỉ cập nhật nó. Khi một khóa không có sẵn trong phần có thể bảo trì, nó sẽ thêm khóa đó vào phần có thể đo được.

Một ví dụ khác cập nhật cùng một bảng bằng cách sử dụng hàm rawset được hiển thị bên dưới.

mytable = setmetatable({key1 = "value1"}, {

   __newindex = function(mytable, key, value)
      rawset(mytable, key, "\""..value.."\"")
   end
})

mytable.key1 = "new value"
mytable.key2 = 4

print(mytable.key1,mytable.key2)

Khi chúng ta chạy chương trình trên, chúng ta sẽ nhận được kết quả sau.

new value	"4"

rawset đặt giá trị mà không sử dụng __newindex có thể đo được. Tương tự, có rawget nhận giá trị mà không cần sử dụng __index.

Thêm hành vi của người vận hành vào bảng

Dưới đây là một ví dụ đơn giản để kết hợp hai bảng bằng cách sử dụng + toán tử:

mytable = setmetatable({ 1, 2, 3 }, {
   __add = function(mytable, newtable)
	
      for i = 1, table.maxn(newtable) do
         table.insert(mytable, table.maxn(mytable)+1,newtable[i])
      end
      return mytable
   end
})

secondtable = {4,5,6}

mytable = mytable + secondtable

for k,v in ipairs(mytable) do
   print(k,v)
end

Khi chúng ta chạy chương trình trên, chúng ta sẽ nhận được kết quả sau.

1	1
2	2
3	3
4	4
5	5
6	6

Khóa __add được bao gồm trong phép đo lường để thêm hành vi của toán tử +. Bảng các phím và toán tử tương ứng được hiển thị bên dưới.

Sr.No. Chế độ & Mô tả
1

__add

Thay đổi hành vi của toán tử '+'.

2

__sub

Thay đổi hành vi của toán tử '-'.

3

__mul

Thay đổi hành vi của toán tử '*'.

4

__div

Thay đổi hành vi của toán tử '/'.

5

__mod

Thay đổi hành vi của toán tử '%'.

6

__unm

Thay đổi hành vi của toán tử '-'.

7

__concat

Thay đổi hành vi của toán tử '..'.

số 8

__eq

Thay đổi hành vi của toán tử '=='.

9

__lt

Thay đổi hành vi của toán tử '<'.

10

__le

Thay đổi hành vi của toán tử '<='.

__gọi

Thêm hành vi của cuộc gọi phương thức được thực hiện bằng cách sử dụng câu lệnh __call. Một ví dụ đơn giản trả về tổng các giá trị trong bảng chính với bảng đã truyền.

mytable = setmetatable({10}, {
   __call = function(mytable, newtable)
   sum = 0
	
      for i = 1, table.maxn(mytable) do
         sum = sum + mytable[i]
      end
	
      for i = 1, table.maxn(newtable) do
         sum = sum + newtable[i]
      end
	
      return sum
   end
})

newtable = {10,20,30}
print(mytable(newtable))

Khi chúng ta chạy chương trình trên, chúng ta sẽ nhận được kết quả sau.

70

__tostring

Để thay đổi hành vi của câu lệnh print, chúng ta có thể sử dụng metamethod __tostring. Một ví dụ đơn giản được hiển thị bên dưới.

mytable = setmetatable({ 10, 20, 30 }, {
   __tostring = function(mytable)
   sum = 0
	
      for k, v in pairs(mytable) do
         sum = sum + v
      end
		
      return "The sum of values in the table is " .. sum
   end
})
print(mytable)

Khi chúng ta chạy chương trình trên, chúng ta sẽ nhận được kết quả sau.

The sum of values in the table is 60

Nếu bạn biết đầy đủ các khả năng của bảng meta, bạn thực sự có thể thực hiện nhiều thao tác sẽ rất phức tạp mà không cần sử dụng đến nó. Vì vậy, hãy cố gắng làm việc nhiều hơn với việc sử dụng các bảng đo lường với các tùy chọn khác nhau có sẵn trong bảng meta như được giải thích trong các mẫu và cũng tạo mẫu của riêng bạn.