수색…


통사론

  • [[local] mt =] getmetatable ( t ) -> ' t '와 연관된 metatable을 검색합니다.
  • [로컬] t =] setmetatable (t, MT) -> '산'에서 't'복귀 't'에 대한 메타 세트

매개 변수

매개 변수 세부
루아 표를 참조하는 변수; 테이블 리터럴이 될 수도 있습니다.
후지산 메타 테이블로 사용할 테이블; 0 개 이상의 메타 메소드 필드를 설정할 수 있습니다.

비고

여기에 언급되지 않은 일부 메타 메소드가 있습니다. 전체 목록과 사용법은 lua 매뉴얼 의 해당 항목을 참조하십시오.

메타 테이블 생성 및 사용

메타 테이블은 루아 객체의 동작을 변경하는 일련의 연산을 정의합니다. 메타 테이블은 특수한 방식으로 사용되는 일반 테이블 일뿐입니다.

local meta = { } -- create a table for use as metatable

-- a metatable can change the behaviour of many things
-- here we modify the 'tostring' operation:
-- this fields should be a function with one argument.
-- it gets called with the respective object and should return a string
meta.__tostring = function (object)
    return string.format("{ %d, %d }", object.x, object.y)
end

-- create an object
local point = { x = 13, y = -2 }
-- set the metatable
setmetatable(point, meta)

-- since 'print' calls 'tostring', we can use it directly:
print(point) -- prints '{ 13, -2 }'

테이블을 메타 메소드로 사용하기

일부 메타 메소드는 함수 일 필요는 없습니다. 가장 중요한 예제는 __index 메타 메소드입니다. 또한 표가 될 수 있으며 조회로 사용됩니다. 이것은 루아에서 클래스를 만드는 데 아주 일반적으로 사용됩니다. 여기서 테이블 (종종 metatable 자체)은 클래스의 모든 연산 (메소드)을 저장하는 데 사용됩니다.

local meta = {}
-- set the __index method to the metatable.
-- Note that this can't be done in the constructor!
meta.__index = meta

function create_new(name)
    local self = { name = name }
    setmetatable(self, meta)
    return self
end

-- define a print function, which is stored in the metatable
function meta.print(self)
    print(self.name)
end

local obj = create_new("Hello from object")
obj:print()

가비지 컬렉터 - __gc 메타 메소드

5.2

루아의 객체는 가비지 수집됩니다. 때로는 개체를 파괴 (수집) 할 때 리소스를 비우거나 메시지를 인쇄하거나 다른 작업을 수행해야 할 때가 있습니다. 이를 위해 __gc metamethod를 사용할 수 있습니다. __gc metamethod는 객체가 파괴 될 때 객체를 인수로 호출합니다. 이 메타 메서드를 일종의 소멸자로 볼 수 있습니다.

이 예제는 작동중인 __gc 메타 메소드를 보여줍니다. t 할당 된 내부 테이블이 가비지 수집 될 때, 수집되기 전에 메시지를 인쇄합니다. 스크립트의 끝 부분에 도달 할 때 외부 테이블과 마찬가지로 :

local meta =
{
    __gc = function(self)
        print("destroying self: " .. self.name)
    end
}

local t = setmetatable({ name = "outer" }, meta)
do
    local t = { name = "inner" }
    setmetatable(t, meta)
end

더 많은 메타 메소드

더 많은 메타 메소드가 있으며 그 중 일부는 산술 연산 (예 : 덧셈, 뺄셈, 곱셈), 비트 연산 (and, or, xor, shift), 비교 (<,>), 그리고 기본 연산 인 ==와 # (평등과 길이). 이 연산들 중 많은 것을 지원하는 클래스를 구축 할 수 있습니다 : 합리적인 산술 호출. 이것은 매우 기본적인 것이지만, 아이디어를 보여줍니다.

local meta = {
    -- string representation
    __tostring = function(self)
        return string.format("%s/%s", self.num, self.den)
    end,
    -- addition of two rationals
    __add = function(self, rhs)
        local num = self.num * rhs.den + rhs.num * self.den
        local den = self.den * rhs.den
        return new_rational(num, den)
    end,
    -- equality
    __eq = function(self, rhs)
        return self.num == rhs.num and self.den == rhs.den
    end
}

-- a function for the creation of new rationals
function new_rational(num, den)
    local self = { num = num, den = den }
    setmetatable(self, meta)

    return self
end

local r1 = new_rational(1, 2)
print(r1) -- 1/2

local r2 = new_rational(1, 3)
print(r1 + r2) -- 5/6

local r3 = new_rational(1, 2)
print(r1 == r3) -- true
-- this would be the behaviour if we hadn't implemented the __eq metamethod.
-- this compares the actual tables, which are different
print(rawequal(r1, r3)) -- false

테이블을 호출 가능하게 만들기

__call 이라는 메타 메서드가 있습니다.이 메타 메서드는 object() 와 같이 함수로 사용될 때 객체의 속성을 정의합니다. 이것은 함수 객체를 만드는 데 사용할 수 있습니다.

-- create the metatable with a __call metamethod
local meta = {
    __call = function(self)
        self.i = self.i + 1
    end,
    -- to view the results
    __tostring = function(self)
        return tostring(self.i)
    end
}

function new_counter(start)
    local self = { i = start }
    setmetatable(self, meta)
    return self
end

-- create a counter
local c = new_counter(1)
print(c) --> 1
-- call -> count up
c()
print(c) --> 2

metamethod가 해당 객체와 함께 호출되면 나머지 모든 인수는 그 이후 함수에 전달됩니다.

local meta = {
    __call = function(self, ...)
        print(self.prepend, ...)
    end
}

local self = { prepend = "printer:" }
setmetatable(self, meta)

self("foo", "bar", "baz")

표의 색인 생성

아마도 메타 테이블의 가장 중요한 사용은 테이블의 인덱싱을 변경할 가능성이 있습니다. 이를 위해 콘텐츠를 읽고 표의 내용을 쓰는 두 가지 작업을 고려해야합니다. 테이블에 해당 키가 없으면 두 조치 모두 트리거됩니다.

독서

local meta = {}

-- to change the reading action, we need to set the '__index' method
-- it gets called with the corresponding table and the used key
-- this means that table[key] translates into meta.__index(table, key)
meta.__index = function(object, index)
    -- print a warning and return a dummy object
    print(string.format("the key '%s' is not present in object '%s'", index, object))
    return -1
end

-- create a testobject
local t = {}

-- set the metatable
setmetatable(t, meta)

print(t["foo"]) -- read a non-existent key, prints the message and returns -1

존재하지 않는 키를 읽는 동안 오류를 발생시키는 데 사용할 수 있습니다.

-- raise an error upon reading a non-existent key
meta.__index = function(object, index)
    error(string.format("the key '%s' is not present in object '%s'", index, object))
end

쓰기

local meta = {}

-- to change the writing action, we need to set the '__newindex' method
-- it gets called with the corresponding table, the used key and the value
-- this means that table[key] = value translates into meta.__newindex(table, key, value)
meta.__newindex = function(object, index, value)
    print(string.format("writing the value '%s' to the object '%s' at the key '%s'",
                         value, object, index))
    --object[index] = value -- we can't do this, see below
end

-- create a testobject
local t = { }

-- set the metatable
setmetatable(t, meta)

-- write a key (this triggers the method)
t.foo = 42

이제 실제 값이 테이블에 어떻게 쓰여지는지 자문 해보십시오. 이 경우에는 그렇지 않습니다. 여기서 문제는 메타 메소드가 메타 메소드를 트리거 할 수 있다는 것입니다.이 메소드는 부정 루프 또는 더 정확하게는 스택 오버 플로우를 초래합니다. 그러면 어떻게 해결할 수 있을까요? 이에 대한 솔루션을 원시 테이블 액세스 라고 합니다 .

원시 테이블 액세스

때로는 메타 메소드를 트리거하고 싶지 않지만 액세스를 둘러싼 영리한 기능을 사용하지 않고 주어진 키를 실제로 쓰거나 읽는 것이 좋습니다. 이를 위해 lua는 원시 테이블 액세스 메소드를 제공합니다.

-- first, set up a metatable that allows no read/write access
local meta = {
    __index = function(object, index)
        -- raise an error
        error(string.format("the key '%s' is not present in object '%s'", index, object))
    end,
    __newindex = function(object, index, value)
        -- raise an error, this prevents any write access to the table
        error(string.format("you are not allowed to write the object '%s'", object))
    end
}

local t = { foo = "bar" }
setmetatable(t, meta)

-- both lines raise an error:
--print(t[1])
--t[1] = 42

-- we can now circumvent this problem by using raw access:
print(rawget(t, 1)) -- prints nil
rawset(t, 1, 42) -- ok

-- since the key 1 is now valid, we can use it in a normal manner:
print(t[1])

이를 통해 ower 이전 __newindex 메소드를 다시 작성하여 실제로 값을 테이블에 쓸 수 있습니다.

meta.__newindex = function(object, index, value)
    print(string.format("writing the value '%s' to the object '%s' at the key '%s'",
                         value, object, index))
    rawset(object, index, value)
end

OOP 시뮬레이션

local Class = {} -- objects and classes will be tables
local __meta = {__index = Class}
-- ^ if an instance doesn't have a field, try indexing the class
function Class.new()
    -- return setmetatable({}, __meta) -- this is shorter and equivalent to:
    local new_instance = {}
    setmetatable(new_instance, __meta)
    return new_instance
end
function Class.print()
    print "I am an instance of 'class'"
end

local object = Class.new()
object.print() --> will print "I am an instance of 'class'"

인스턴스 메소드는 첫 번째 인수로 객체를 전달하여 작성할 수 있습니다.

-- append to the above example
function Class.sayhello(self)
    print("hello, I am ", self)
end
object.sayhello(object) --> will print "hello, I am <table ID>"
object.sayhello() --> will print "hello, I am nil"

이것에 대한 구문 론적 설탕이 있습니다.

function Class:saybye(phrase)
    print("I am " .. self .. "\n" .. phrase)
end
object:saybye("c ya") --> will print "I am <table ID>
                      -->             c ya"

클래스에 기본 필드를 추가 할 수도 있습니다.

local Class = {health = 100}
local __meta = {__index = Class}

function Class.new() return setmetatable({}, __meta) end
local object = Class.new()
print(object.health) --> prints 100
Class.health = 50; print(object.health) --> prints 50
-- this should not be done, but it illustrates lua indexes "Class"
-- when "object" doesn't have a certain field
object.health = 200 -- This does NOT index Class
print(object.health) --> prints 200


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow