《 Programming in Lua 3 》 독서 노트 (10)
날짜: 2014.7.11
Part Ⅱ
Metatables and Metamethods
Lua 에 서 는 table 을 직접 더하기, 비교 등 으로 조작 할 수 없습니다.메타 테이블 (Metatables) 을 사용 하지 않 는 한.메타 표 는 두 table 의 직접적인 추가 작업 을 정의 하 는 등 요 소 를 변경 할 수 있 습 니 다.Lua 는 두 table 의 추가 작업 을 처리 할 때 먼저 두 table 에 메타 표 가 있 는 지, 메타 표 에 가 있 는 지 확인 합 니 다.add 메타 방법 필드, 이 필드 가 있 으 면 lua 는 이 필드 에서 정 의 된 작업 에 따라 두 table 의 추가 작업 을 수행 합 니 다.
Lua 의 각 유사 한 변 수 는 연 결 된 메타 표 가 있 습 니까?(도대체 있 습 니까?) 그리고 table 과 userdata 는 각각 독립 된 메타 표를 가지 고 있 습 니 다.기본적으로 새로 만 든 table 은 메타 테이블 이 없습니다.
e.g.
t = {}
print(getmetatable(t)) --nil
이때 우 리 는 setmetatable 방법 을 통 해 원 표를 설정 할 수 있 습 니 다. 원 표 는 사실 하나의 table 에 해당 합 니 다.
e.g.
t1 = {}
setmetatable(t,t1)
print(getmetatable(t) == t1) --ture
물론 lua 에서 저 희 는 table 에 대해 서 만 setmetatable 작업 을 수행 할 수 있 습 니 다. 다른 유형의 변 수 를 실행 하려 면 C 코드 를 사용 해 야 합 니 다.책 에 있 는 string 라 이브 러 리 는 string 형식 변수 에 메타 표를 설정 하 는 작업 과 관련 이 있 습 니 다.나머지 유형의 변 수 는 기본적으로 메타 표 가 없 습 니까?
print(getmetatable("ss")) -- table
print(getmetatable(10)) --nil
Arithmetic Metamethods
산술 연산 원 방법
여기 서 메타 표 의 사용 을 소개 합 니 다. 여기 서 하나의 table 로 set 를 표시 합 니 다. 우 리 는 연산 set 의 집합 등 조작 이 필요 합 니 다.
e.g.
Set = {}
local mt = {} --metatable for sets
function Set.new(l) -- set,
local set = {}
setmetatable(set,mt)
for _ v in ipairs(l) do set[v] = true end
return set
end
이렇게 하면 매번 우리 가 set 를 새로 만 들 때마다 같은 메타 테이블 이 있 습 니 다.
s1 = Set.new{10,20,11,13}
s2 = Set.new{30,1}
print(getmetatable(s1)) --table: 0x7fa1eb4093a0
print(getmetatable(s2)) --table: 0x7fa1eb4093a0
원 표 에 원 을 추가 하 는 방법:add 필드 는 table 이 추가 작업 을 수행 하면
mt.__add = Set.union --이때 의 에 주의 하 세 요.dd 필드 는 사용 할 수 없습니다. Set. union 이 아직 정의 되 지 않 았 기 때문에 이 코드 도 Set. union 을 정의 한 후에 두 어야 합 니 다. 그렇지 않 으 면 오 류 를 보고 할 수 있 습 니 다.정확 한 용법 은 먼저 정 의 를 내 린 다음 에 값 을 부여 하 는 것 이다.
-- 만약 mt.add = Set.union
-- Set.union
function Set.union( a,b )
local res = Set.new{}
for k in pairs(a) do
res[k] = true
end
for k in pairs(b) do
res[k] = true
end
return res
end
-- 이때
s3 = s1 + s2 잘못 보고 --attempt to perform arithmetic on global 's1' (a table value)
-- mt. 를add = Set. union 은 Set. union 을 정의 한 다음 에 놓 습 니 다.
마찬가지 로 설정mul 원 방법 도 비슷 한 요구 입 니 다.
-- Set.intersection
function Set.intersection( a,b )
local res = Set.new{}
for k in pairs(a) do
res[k] = b[k]
end
return res
end
mt.__mul = Set.intersection
모든 산술 연산 원 방법:
__add (더하기),mul (곱 하기),sub (빼 기),div (제외),unm (마이너스),mod (모델 링),pow (멱),concat (연결)
Lua 는 두 변수의 산술 연산 을 처리 할 때 서로 다른 유형의 변 수 를 대상 으로 합 니 다. 예 를 들 어
e.g.
s = Set.new {1,2,3}
s = s + 8
이 때 실행 하면 오류 가 발생 합 니 다.
--bad argument #1 to 'pairs' (table expected, got number)
두 변 수 를 처리 하 는 산술 연산 은 첫 번 째 변수 가 원 방 법칙 이 첫 번 째 변 수 를 사용 하 는 원 방법 을 정의 하면 두 번 째 요소 의 원 방법 을 고려 하지 않 는 다.첫 번 째 는 없고 두 번 째 는 있 으 면 두 번 째 것 을 사용한다.그렇지 않 으 면 잘못 보고 할 것 이다.
따라서 더 좋 은 제어 프로그램 이 실행 되 기 위해 서 는 두 변 수 를 같은 유형 으로 같은 메타 표를 가지 도록 제한 해 야 합 니 다.add 를 예 로 들 면 다음 과 같이 조작 할 수 있 습 니 다.
function Set.union( a,b )
if getmetatable(a) ~= mt or getmetatable(b) ~= mt then
error("xxx",2) -- 2,
local res = Set.new{}
for k in pairs(a) do
res[k] = true
end
for k in pairs(b) do
res[k] = true
end
return res
end
Relational Metamethods
관계 연산 원 방법
Lua 의 관계 연산 원 방법 은 주로 다음 과 같다.
__eq (대등),lt (이하),le.다른 관계 조작 부호 에 대해 Lua 는 직접 전환 을 했다. a ~ = b 는 not (a = = b), a > b 는 b < a, a > = b 는 b < = a 에 해당 한다.
관계 연산 원 방법의 구체 적 인 사용 은 앞에서 언급 한 산술 연산 원 방법 과 유사 하 다.
주의해 야 할 것 은 두 변수의 메타 방법 이 다 를 때 같은 관계 연산 을 실행 하면 false 로 돌아 갑 니 다.
Library-Defined Metamethods
라 이브 러 리 정의 메타 방법
__tostring 메타 방법
tostring 함 수 를 호출 할 때 함 수 는 먼저 변수 가 있 는 지 찾 습 니 다.tostring 메타 방법:
위 글 과 같이:
s = Set.new{1,2,2}
print(s) --table: 0x7f8349403d30
print(getmetatable(s)) --table: 0x7f8349409fd0
이 때 인쇄 된 것 은 그 값 이 아니 지만, 원 표 도 아니다
--to string
function Set.tostring( set )
local l = {}
for e in pairs(set) do
l[#l + 1] = e
end
return "{" .. table.concat(l," , ") .. "}"
end
mt.__tostring = Set.tostring
print(s) --{1,2,2}
메타 방법 을 설정 한 후에 야 값 을 정확하게 출력 할 수 있 습 니 다.
물론 우 리 는 일정한 방법 을 통 해 우리 의 원 표를 보호 할 수 있다. setmetatabe 와 getmetatable 도 원 방법 을 사용 했다. 우 리 는 이러한 특성 에 따라 우리 의 목적 을 달성 할 수 있다.
e.g.
mt.__metatable = "cannot change"
s1 = Set.new{}
print(getmetatable(s1)) --cannot change
우리 가 원 표를 바 꾸 고 싶 을 때
e.g.
setmetatable(s1,mt) --error:cannot change a protected metatable
잘못 보고 할 수 있 으 니, 그 원 표를 수정 해 서 는 안 된다. 이렇게 하면 우리 가 원 표를 보호 해 야 하 는 목적 을 달성 할 수 있다.
Table-Access Metamethods
Lua 는 메타 테이블 을 통 해 table 에 존재 하지 않 는 요 소 를 수정 하고 접근 하 는 행 위 를 제어 할 수 있 습 니 다.
The __index metamehod
우리 가 table 에 존재 하지 않 는 요 소 를 방문 하려 고 할 때, 우리 가 얻 은 값 은 nil 입 니 다.이것 은 일반적인 의미 에서 이 루어 진 것 입 니 다. 사실은 우리 가 table 에 존재 하지 않 는 요 소 를 방문 할 때 컴 파일 러 가 을 찾 도록 촉발 합 니 다.index 메타 방법, 이 방법 이 없 을 때 nil 로 돌아 갑 니 다.이 메타 방법 이 정의 되면 이 방법 이 정의 한 동작 을 되 돌려 줍 니 다.
이 특성 은 우리 가 계승 체 제 를 사용 하고 기본 변 수 를 계승 할 때 큰 도움 이 되 며 책 에서 도 이 를 예 로 들 어 설명 했다.
-- 기본 변수 가 있 는 table
prototype = {x = 0,y = 0,width = 100,height = 100}
원 표
mt = {}
구조 함수
function new(o)
setmetatable(o,mt)
return o
end
-- 메타 법 정의
mt.__index = function(_,key)
return prototype[key]
end
-- 새로운 table 을 만 들 고 계승 체 제 를 사용 하려 면 기본 변수의 table 이 필요 하 다.
w = new{x = 10,y = 20}
print(w.width) --100
이때 w 는 prototype 의 값 을 사 용 했 습 니 다.
__index 메타 방법 은 함수 가 필요 하지 않 고 table 일 수도 있 습 니 다.이 방법 이 함수 일 때 Lua 는 함수 에서 정 의 된 동작 을 수행 합 니 다. table 일 때 Lua 는 table 에서 직접 접근 동작 을 수행 합 니 다.
함수. rawget(t,i) table 각 요 소 를 방문 할 때 호출 하지 않 을 수 있 습 니 다index 작업. t 에 raw 접근 을 실행 합 니까?무슨 뜻
The __newindex metamethod
이 메타 방법의 역할 은 table 의 요소 값 을 업데이트 할 때 나타 납 니 다.우리 가 table 에 존재 하지 않 는 키 에 값 을 부여 하려 고 할 때 컴 파 일 러 는new index 의 메타 방법 은 컴 파일 러 가 있 으 면 이 방법 이 정의 한 작업 을 수행 합 니 다. 그렇지 않 으 면 직접 값 을 부여 합 니 다.여기 도 함수 가 하나 있어 요. rawset (t, k, v), 이 함 수 는 원 을 돌 리 는 방법 으로 t 에서 키 k 에 값 v 를 직접 설정 합 니 다.
책 에서 언급 한 효과 적 인 결합index 와new index 두 메타 방법의 사용 은 읽 기 전용 table, 기본 값 을 가 진 table 등 강력 한 디자인 기 교 를 가 져 올 것 입 니 다.
Tables with default values
table 은 기본 값 을 가지 고 있 습 니 다. 그 원 리 는 우리 가 table 에 존재 하지 않 거나 할당 되 지 않 은 키 를 방문 할 때 반환 값 은 고정 값 입 니 다. 여기 서 와 관련 됩 니 다.index 메타 방법
e.g.
function setDefault( t,d )
local mt = {__index = function ( ... )
return d
end}
setmetatable(t,mt)
end
tab = {x = 10,y = 20}
print(tab.x,tab.z) --10,nil
setDefault(tab,0)
print(tab.x,tab.z) --10,0
이 동작 은 tab 에 기본 값 0 을 설정 합 니 다. tab 에 정의 되 지 않 거나 존재 하지 않 는 요소 에 접근 하려 면 반환 값 은 0 입 니 다.
여러 개의 다른 table 에 여러 개의 기본 값 을 설정 하 는 작업 을 수행 합 니 다.
e.g.
local mt = {__index = function (t) return t.___ end}
function setDefault (t,d)
t.___ = d
setmetatable(t,mt)
end
이 기술 은 메타 표 의 정 의 는 함수 의 외부 에 있 고 기본 값 을 기본 값 으로 설정 할 table 자체 의 내부 에 저장 하 는 것 입 니 다.
이름 충돌 방지 동작:
e.g.
local key = {} -- table key
local mt = {__index = function (t) return t[key] end}
function setDefault (t,d)
t[key] = d
setmetatable(t,mt)
end
Tracking table accesses
유효한 사용index 와new index 는 table 에 대한 접근 과 할당 작업 을 감시 하 는 데 도움 을 줄 수 있 습 니 다.proxy (에이전트) 를 사용 하면 table 에 대한 모든 접근 동작 을 추적 하고 접근 하 는 값 을 추적 할 수 있 습 니 다.책 에서 언급 한 것 은 table 이 비어 있 을 때 만 모든 접근 동작 을 포착 할 수 있 습 니 다. 왜 요?
t = {} --original table
--keep a private access to the original table
local _t = t
--create proxy
t = {}
--create metatable
local mt = {
__index = function ( t,k )
print("*access to element " .. tostring(k))
return _t[k]
end,
__newindex = function ( t,k,v )
print("*update of element " .. tostring(k) .. " to " .. tostring(v))
_t[k] = v --update original table
end
}
setmetatable(t,mt)
t[2] = "hello"
print(t[2])
인쇄 되 어 있 으 며, table 이 할당 에서 접근 하 는 과정 을 추적 하 였 습 니 다.
*update of element 2 to hello
*access to element 2
hello
Read-only tables
읽 기 전용 테이블
table 만 읽 는 원 리 는 주로 table 에 값 을 부여 하려 고 할 때 제한 하 는 것 입 니 다. 여 기 는new index 메타 방법의 사용.
e.g.
--read only table
function readOnly (t)
local proxy = {}
local mt = {
__index = t,
__newindex = function (t,k,v)
error("attempt to update a read-only table",2) -- , 2, 。
end
}
setmetatable(proxy,mt)
return proxy
end
을 통 해new index 메타 방법 에서 적당 한 수정 을 하면 우리 의 table 을 읽 기 전용 table 로 바 꿀 수 있 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
로그'메타프로그램 루비 버전 2'3장 읽기동적 방법 Object#send 호출 방법은 약간 메모와 Object#send obj.send(:my_method, 3) Object#send를 사용하면 어떤 방법으로든 호출할 수 있습니다. privete 방법을 호...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.