__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) -- 출력: nilreadOnly.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) -- 출력: 100player는 자체 키를 가지지 않으므로 모든 대입은 __newindex를 거치고, 모든 읽기는 __index를 통해 data로 이어집니다.
챌린지
쉬움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
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
논리와 흐름 제어의 모든 레슨
직접 연습해 보세요: 온라인 Lua 컴파일러