Menu
CoddyTech

__newindex 메타메소드

Coddy Lua 여정의 논리와 흐름 제어 섹션에 포함된 레슨. 54개 중 19번째.

테이블에 존재하지 않는 키를 읽으려고 할 때 어떤 일이 일어나는지 __index가 제어한다는 것을 배웠습니다. 이제 그 짝인 __newindex를 알아보겠습니다. __newindex는 테이블에 아직 없는 키에 값을 할당할 때 어떤 일이 일어나는지 제어합니다.

__newindex 메타메서드는 테이블에 현재 존재하지 않는 키에 값을 할당하려고 할 때마다 호출됩니다. 이를 통해 변경이 발생하기 전에 가로채고 제어할 수 있습니다.

다음은 테이블에 새 키가 추가되지 않도록 방지하는 간단한 예제입니다:

local readOnly = {}
local meta = {
    __newindex = function(table, key, value)
        print("Cannot add key: " .. key)
    end
}

setmetatable(readOnly, meta)

readOnly.name = "Alice"  -- 출력: Cannot add key: name
print(readOnly.name)     -- 출력: nil

readOnly.name = "Alice"를 설정하려고 하면 Lua는 테이블에 name이 존재하지 않는다는 것을 확인합니다. Lua는 이를 추가하는 대신 __newindex 함수를 세 개의 인수와 함께 호출합니다. 인수는 테이블 자체, 설정할 키, 할당할 값입니다.

이 예제에서 함수는 메시지를 출력하기만 하며 실제로는 아무것도 저장하지 않습니다.

__newindex를 사용해 데이터를 테이블에 넣기 전에 유효성을 검사할 수도 있습니다.

local player = {}
local meta = {
    __newindex = function(t, key, value)
        if key == "health" and type(value) ~= "number" then
            print("Health must be a number!")
        else
            rawset(t, key, value)
        end
    end
}

setmetatable(player, meta)

player.health = "high"  -- 출력: Health must be a number!
player.health = 100     -- 허용됨, rawset으로 저장됨
player.health = "high"  -- 메시지 없음: 이제 health가 존재함

두 번째 예제에서 rawset()을 사용하는 점에 주목하세요. 이 함수는 메타테이블을 우회하여 테이블에 값을 직접 설정합니다.

그것이 없으면 값을 설정할 때 __newindex가 다시 실행되어 무한 루프가 발생합니다.

__newindex는 테이블에 없는 키에 대해서만 실행되므로, 이 검사는 각 키의 최초 할당을 보호합니다. rawset이 health를 저장하고 나면 이후 할당은 해당 값을 직접 변경합니다. 모든 할당을 검사하려면 테이블 자체는 비워 두고, __index를 통해 읽어 오는 두 번째 테이블에 값을 저장하세요.

local data = {}
local player = setmetatable({}, {
    __index = data,
    __newindex = function(t, key, value)
        if key == "health" and type(value) ~= "number" then
            print("Health must be a number!")
        else
            data[key] = value
        end
    end
})

player.health = 100
player.health = "high"  -- 출력: Health must be a number!
print(player.health)    -- 출력: 100

player는 자체 키를 가지지 않으므로 모든 대입은 __newindex를 거치고, 모든 읽기는 __index를 통해 data로 이어집니다.

challenge icon

챌린지

쉬움

createValidatedTable 함수를 작성하세요. 이 함수는 key와 value를 받아 새 키에 문자열 값만 허용하는 테이블을 반환합니다.

빈 테이블을 만들고 값의 유형을 검증하는 __newindex 메타테이블을 연결하세요. 문자열이 아닌 값을 추가하려고 하면 rawset()을 사용해 그 대신 문자열 "invalid"를 저장하세요. 문자열 값은 rawset()을 사용해 일반적으로 저장하세요.

로직:

  • 빈 테이블을 만듭니다
  • 테이블, 키, 값을 받는 __newindex 메타테이블을 만듭니다
  • __newindex 내부에서 type(value) == "string"을 사용해 값이 문자열인지 확인합니다
  • 문자열이면 rawset(t, key, value)를 사용해 저장합니다
  • 문자열이 아니면 rawset(t, key, "invalid")를 사용해 그 대신 "invalid"를 저장합니다
  • setmetatable()을 사용해 메타테이블을 테이블에 연결합니다
  • rawset()을 사용해 테이블에 초기 키-값 쌍을 추가합니다(메타테이블 우회)
  • 테이블을 반환합니다

매개변수:

  • key (문자열): 테이블에 추가할 초기 키
  • value (문자열): 테이블에 추가할 초기 값

반환값: 문자열 값만 허용하도록 검증하고 초기 키-값 쌍을 포함하는 테이블(테이블)

직접 해보기

function createValidatedTable(key, value)
    -- 여기에 코드를 작성하세요
end
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

논리와 흐름 제어의 모든 레슨

직접 연습해 보세요: 온라인 Lua 컴파일러