__newindex 메타메소드
Coddy Lua 여정의 Logic & Flow 섹션에 포함된 레슨 — 54개 중 19번째.
여러분은 __index가 테이블에 존재하지 않는 키를 읽으려고 할 때 어떤 일이 일어나는지 제어하는 방법을 배웠습니다. 이제 그 짝꿍인 __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()의 사용에 주목하세요. 이 함수는 메타테이블을 우회하여 테이블에 값을 직접 설정합니다.
그것이 없다면, 값을 설정할 때 __newindex가 다시 호출되어 무한 루프가 발생할 것입니다.
챌린지
쉬움새로운 키에 대해 문자열 값만 허용하는 테이블을 반환하는 createValidatedTable 함수를 작성하세요. 이 함수는 key와 value를 인자로 받습니다.
빈 테이블을 생성하고, 값의 타입을 검증하는 __newindex가 포함된 메타테이블을 연결하세요. 만약 누군가 문자열이 아닌 값을 추가하려고 하면, rawset()을 사용하여 "invalid"라는 문자열을 대신 저장하세요. 문자열 값인 경우에는 rawset()을 사용하여 정상적으로 저장합니다.
로직:
- 빈 테이블을 생성합니다.
- 테이블, 키, 값을 전달받는
__newindex가 포함된 메타테이블을 생성합니다. __newindex내부에서type(value) == "string"을 사용하여 값이 문자열인지 확인합니다.- 문자열인 경우,
rawset(t, key, value)를 사용하여 저장합니다. - 문자열이 아닌 경우,
rawset(t, key, "invalid")를 사용하여"invalid"를 대신 저장합니다. setmetatable()을 사용하여 메타테이블을 테이블에 연결합니다.rawset()을 사용하여 초기 키-값 쌍을 테이블에 추가합니다 (메타테이블을 우회함).- 테이블을 반환합니다.
매개변수:
key(string): 테이블에 추가할 초기 키value(string): 테이블에 추가할 초기 값
반환값: 초기 키-값 쌍을 포함하며, 문자열 값만 허용하는 검증 기능이 있는 테이블 (table)
치트 시트
__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__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(t, key, value)를 사용하세요. 이는 __newindex 내부에서 값을 설정할 때 무한 루프가 발생하는 것을 방지합니다.
직접 해보기
function createValidatedTable(key, value)
-- 여기에 코드를 작성하세요
end
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.