Introduction 
: 루아의 모든 테이블과 유저데이터는 각각 메타테이블이 따로있고, 테이블과 유저데이터를 제외한 다른 타입은 하나의 메타테이블을 공유하는 형태다.

새로운 테이블을 생성하면 항상 메타테이블이 없이 생성된다. 

t = {}
print(getmetatable(t)) --> nil 

t1 = {} 
setmetatable(t, t1) 
print(getmetatable(t) == t1) --> true

루아 코드로는 테이블의 메타테이블만 설정할 수 있다. 다른 타입의 메타 테이블을 조작하려면 직접 C 코드를 이용해야 한다. 

그리고 테이블은 자신의 메타테이블이 될 수도 있는데, 이때는 자신의 행위를 기술하는 데 사용된다. 


1. 산술 메타메서드 
: 우선 Set을 구현해보자. 

Set = {} 

function Set.new (l)
    local set = {}
    for _, v in ipairs(l) do set[v] = true end
       
    return set
end

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

function Set.intersection (a, b) 
    local res = Set.new{}
    for k in pairs(a) do
        res[k] = b[k]
    end

    return res
end

이제 두 집합의 합집합을 구할 때 덧셈 연산자 "+"를 사용하려 한다. 이를 위해 Set을 표현하는 모든 테이블이 하나의 메타테이블을 공유하도록 할 것이다. 이 메타테이블에서 덧셈 연산자를 어떻게 처리해야 하는지 정의해야 한다. 

local mt = {} -- Set에 대한 메타테이블 

다음 단계로, Set을 생성하는 Set.new 함수를 수정한다. 

function Set.new (l)
    local set = {}
    setmetatable(set, mt)
    for _, v in ipairs(l) do set[v] = true end 
       
    return set
end

마지막으로 메타테이블에 덧셈을 처리하는 방법을 설멸하는 메타메서드인 "__add" 추가한다. 

mt.__add = Set.union

s1 = Set.new{10, 20, 30, 50}
s2 = Set.new{30, 1}
s3 = s1 + s2
Set.print(s3) --> {1, 10, 20, 30, 50}

동일한 방식으로 곱셈 연산자를 이용해서 교집합을 구하도록 할 수 있다. 

mt.__mul = Set.intersection
Set.print((s1 + s2) * s1) --> {10, 20, 30, 50} 

메타테이블에는 산술 연산자에 대응하는 필드명이 있다. __add, __mul 외에 뺄셈을 위한 __sub, 나눗셈을 위한 __div, 부정 연산을 위한 __unm, 나머지 연산을 위한 __mod, 지수 연산을 위한 __pow가 있다. 그리고 붙이기 연산을 위한 __concat 필드도 정의할 수 있다. 


2. 관계 메타메서드 
: 메타테이블을 이용하면 관계 연산자에도 의미를 부여할 수 있다. 
- __eq : = 
- __lt : < (작음)
- __le : <= (작거나 같음) 
위 세개의 관계 연산자는 별도의 메타메서드로 제공되지는 않는다. 대신 루아는 a~=b를 not(a==b)로 표현하듯이 not을 써서 표현할 수 있다. 


3. 라이브러리에 정의된 메타메서드
: print() 함수는 인자를 받으면 tostring을 호출해서 출력한다. 
위 Set에 다음과 같은 함수가 있다고 해보자. 

function Set.tostring (set)
    local whole = {}
    for e in pairs(set) do
        whole[#whole + 1] = e
    end
    
    return "{" .. table.concat(whole, ", ") .. "}"
end

위 함수가 있으면 해당 함수를 tostring에 대한 메타메서드로 지정할 수 있다. 

mt.__tostring = Set.tostring

s1 = Set.new{10, 4, 5}
print(s1) --> { 4, 5, 10 }


'Lua Script' 카테고리의 다른 글

[Lua] 클래스  (0) 2018.04.01
[Lua] 반복자  (0) 2018.03.28
[Lua] 함수의 내부  (0) 2018.03.28
[Lua] 함수  (0) 2018.03.27
[Lua] 문장  (0) 2018.03.27
Posted by 홍성곤
,