루아 메타테이블
Lua 테이블에서는 해당 키에 액세스하여 값을 얻을 수 있지만 두 테이블에서 작업을 수행할 수는 없습니다.
따라서 Lua는 테이블의 동작을 변경할 수 있는 메타테이블(Metatable)을 제공합니다.
예를 들어 메타테이블을 사용하면 Lua가 두 테이블의 추가 연산 a+b를 계산하는 방법을 정의할 수 있습니다.
Lua는 두 개의 테이블을 추가하려고 할 때 두 테이블 중 하나에 메타테이블이 있는지 먼저 확인한 다음 "__add"라는 필드가 있는지 확인하고 해당 값을 호출합니다. "__add"와 같은 실시간 필드의 경우 해당 값(종종 함수 또는 테이블)은 "메타 메서드"입니다.
메타테이블을 처리하는 데 매우 중요한 두 가지 함수가 있습니다:
setmetatable(table, Metatable): 지정된 테이블에 대한 메타테이블 설정(메타테이블) , __metatable 키 값이 메타테이블(메타테이블)에 존재하면 setmetatable이 실패합니다.
getmetatable(table): 객체의 메타테이블을 반환합니다.
다음 예는 지정된 테이블에 대한 메타테이블을 설정하는 방법을 보여줍니다.
mytable = {} -- 普通表 mymetatable = {} -- 元表 setmetatable(mytable,mymetatable) -- 把 mymetatable 设为 mytable 的元表
위 코드는 한 줄에 직접 작성할 수도 있습니다.
mytable = setmetatable({},{})
다음이 반환됩니다. 객체 메타테이블:
getmetatable(mytable) -- 这回返回mymetatable
__index 메타메서드
가장 일반적으로 사용되는 메타테이블 키입니다.
키로 테이블에 액세스할 때 키에 값이 없으면 Lua는 테이블의 메타테이블에서 __index 키를 찾습니다(메타테이블이 있다고 가정). __index에 테이블이 포함되어 있으면 Lua는 테이블에서 해당 키를 찾습니다.lua 명령을 사용하여 대화형 모드로 들어가 볼 수 있습니다.
$ lua Lua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio > other = { foo = 3 } > t = setmetatable({}, { __index = other }) > t.foo 3 > t.bar nil
__index에 함수가 포함되어 있으면 Lua는 해당 함수를 호출하고 테이블과 키는 매개변수가 함수에 전달됩니다.
__index 메타 메소드는 요소가 테이블에 존재하는지 확인합니다. 존재하지 않는 경우 반환 결과는 nil이고, 존재하는 경우 결과는 __index에 의해 반환됩니다.
mytable = setmetatable({key1 = "value1"}, { __index = function(mytable, key) if key == "key2" then return "metatablevalue" else return nil end end }) print(mytable.key1,mytable.key2)
인스턴스 출력 결과:
value1 metatablevalue
인스턴스 분석:
mytable 테이블 할당은{key1 = "value1"}.
mytable은 메타테이블을 설정하며, 메타메서드는 __index입니다.
mytable 테이블에서 key1을 찾습니다. 발견되지 않으면 해당 요소를 반환합니다.
mytable 테이블에서 key2를 찾습니다. 찾을 수 없으면 메타테이블 값을 반환합니다.
메타테이블에 __index 메서드가 있는지 확인합니다. __index 메서드가 함수인 경우 해당 함수를 호출합니다.
메타 메소드에서 "key2" 키 매개변수가 전달되었는지 확인합니다(mytable.key2가 설정됨). "key2" 매개변수가 전달되면 "metatablevalue" 그렇지 않으면 mytable의 해당 값이 반환됩니다.
위 코드를 다음과 같이 간단하게 작성할 수 있습니다.
mytable = setmetatable({key1 = "value1"}, { __index = { key2 = "metatablevalue" } }) print(mytable.key1,mytable.key2)
요약
루아가 테이블을 검색할 때 요소 규칙은 실제로 다음 3단계입니다.
1. 요소를 찾으면 해당 요소를 반환합니다.
2. 테이블에 메타테이블이 있는지 확인합니다. 메타테이블이 있으면 nil을 반환합니다.
3. 메타테이블에 __index 메서드가 있는지 확인합니다. __index 메서드가 nil이면 nil을 반환하고, __index 메서드가 테이블이면 1, 2, 3을 반복합니다. __index 메서드가 함수인 경우 해당 함수의 반환 값이 반환됩니다.
__newindex 메타 메서드
__newindex 메타 메서드는 테이블을 업데이트하는 데 사용되며 __index는 테이블에 액세스하는 데 사용됩니다.
테이블의 누락된 인덱스에 값을 할당하면 인터프리터는 __newindex 메타메서드를 찾습니다. 존재하는 경우 할당을 수행하지 않고 이 함수를 호출합니다.
다음 예에서는 __newindex 메타 메서드의 적용을 보여줍니다.
mymetatable = {} mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable }) print(mytable.key1) mytable.newkey = "新值2" print(mytable.newkey,mymetatable.newkey) mytable.key1 = "新值1" print(mytable.key1,mymetatable.key1)
위 예의 실행 출력은 다음과 같습니다.
value1 nil 新值2 新值1 nil
위 예에서 메타- __newindex 메소드가 테이블에 설정되어 있습니다. 새 인덱스 키(newkey)에 값을 할당하면(mytable.newkey = "new value 2") 값을 할당하지 않고 메타메서드가 호출됩니다. 기존 인덱스 키(key1)가 할당되면 메타 메서드 __newindex를 호출하지 않고 값이 할당됩니다.
다음 예에서는 rawset 함수를 사용하여 테이블을 업데이트합니다.
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)
위 예의 실행 출력은 다음과 같습니다.
new value "4"
테이블에 연산자 추가
다음 예제에서는 두 테이블의 추가 작업을 보여줍니다.
-- 计算表中最大值,table.maxn在Lua5.2以上版本中已无法使用 -- 自定义计算表中最大值函数 table_maxn function table_maxn(t) local mn = 0 for k, v in pairs(t) do if mn < k then mn = k end end return mn end -- 两表相加操作 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
위 예제 실행의 출력 결과는 다음과 같습니다.
1 1 2 2 3 3 4 4 5 5 6 6
__add 키가 메타테이블에 포함됩니다. 그리고 덧셈 연산이 수행됩니다. 테이블의 해당 작업 목록은 다음과 같습니다.
模式 | 描述 |
---|---|
__add | 对应的运算符 '+'. |
__sub | 对应的运算符 '-'. |
__mul | 对应的运算符 '*'. |
__div | 对应的运算符 '/'. |
__mod | 对应的运算符 '%'. |
__unm | 对应的运算符 '-'. |
__concat | 对应的运算符 '..'. |
__eq | 对应的运算符 '=='. |
__lt | 对应的运算符 '<'. |
__le | 对应的运算符 '<='. |
__call 메타메서드
__call 메타메서드는 Lua가 값을 호출할 때 호출됩니다. 다음 예에서는 테이블의 요소 합계 계산을 보여줍니다.
-- 计算表中最大值,table.maxn在Lua5.2以上版本中已无法使用 -- 自定义计算表中最大值函数 table_maxn function table_maxn(t) local mn = 0 for k, v in pairs(t) do if mn < k then mn = k end end return mn end -- 定义元方法__call 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))
위 예의 실행 출력은 다음과 같습니다.
70
__tostring 메타메서드
__tostring 메타메소드는 테이블의 출력 동작을 수정하는 데 사용됩니다. 다음 예에서는 테이블의 출력 내용을 사용자 정의했습니다.
mytable = setmetatable({ 10, 20, 30 }, { __tostring = function(mytable) sum = 0 for k, v in pairs(mytable) do sum = sum + v end return "表所有元素的和为 " .. sum end }) print(mytable)
위 예를 실행한 결과는 다음과 같습니다.
表所有元素的和为 60
이 기사에서 우리는 메타테이블은 코드 기능을 크게 단순화할 수 있습니다. 따라서 Lua의 메타테이블을 이해하면 더 간단하고 더 나은 Lua 코드를 작성할 수 있습니다.