읽기 전용 테이블
Coddy Lua 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 70개 중 46번째.
클로저는 진정한 은닉성을 제공하지만, 생성자 내부에서 메서드를 정의해야 합니다. 다른 유스케이스를 위한 또 다른 접근 방식이 있습니다. 바로 객체를 생성한 후 읽기 전용으로 만드는 것입니다. 이는 고정된 점의 좌표와 같이 필드를 볼 수는 있지만 변경할 수는 없게 만들고 싶을 때 유용합니다.
__newindex 메타메서드는 테이블에 새로운 값을 할당하려는 시도를 가로챕니다. 모든 할당을 차단하도록 설정함으로써 객체를 동결(freeze)할 수 있습니다:
local ImmutablePoint = {}
function ImmutablePoint.new(x, y)
local data = {x = x, y = y}
local proxy = {}
setmetatable(proxy, {
__index = data,
__newindex = function()
error("Cannot modify immutable object")
end
})
return proxy
end비결은 프록시 테이블을 사용하는 것입니다. 실제 데이터는 data에 있으며, 사용자는 비어 있는 proxy와 상호작용합니다.
읽을 때 __index는 data에서 값을 가져옵니다. 쓸 때는 대신 __newindex가 트리거되며, 이를 차단합니다:
local p = ImmutablePoint.new(10, 20)
print(p.x) -- 10 (읽기 가능)
p.x = 50 -- 오류: 불변 객체는 수정할 수 없습니다이 패턴은 설정 객체, 수학적 상수 또는 초기화 후 절대 변경되지 않아야 하는 모든 데이터에 유용합니다. 객체는 완전히 읽기 가능한 상태로 유지되지만, 수정할 수는 없습니다.
챌린지
쉬움읽기 전용 설정 객체를 생성하는 ImmutableConfig 클래스를 만들어 봅시다! 이 설정 객체는 생성된 후 설정을 읽을 수는 있지만, 수정하려는 모든 시도는 완전히 차단해야 합니다.
코드는 다음 두 개의 파일로 구성됩니다:
ImmutableConfig.lua: 고정된 설정 객체를 생성하는 모듈을 만듭니다..new(appName, version, maxUsers)함수는 이 세 가지 값을 내부적으로 저장한 다음, 모든 필드를 읽을 수는 있지만 수정은 방지하는 프록시 테이블을 반환해야 합니다. 누군가 값을 변경하려고 하면 실제 에러를 발생시키는 대신Error: Config is read-only를 출력해야 합니다.main.lua: ImmutableConfig를 실제로 실행해 봅니다! 설정 값으로 사용할 세 개의 입력을 읽고, 설정 객체를 생성한 후, 다음을 통해 올바르게 작동하는지 증명하세요:- 세 가지 원본 값을 모두 출력합니다.
maxUsers필드 수정을 시도합니다 (이때 에러 메시지가 출력되어야 합니다).maxUsers를 다시 출력하여 실제로 변경되지 않았음을 증명합니다.
세 가지 입력을 받게 됩니다:
- 애플리케이션 이름 (문자열)
- 버전 (문자열)
- 최대 사용자 수 (숫자)
출력은 설정 값, 수정 시도 시 발생하는 에러, 그리고 값이 변경되지 않았음을 확인하는 내용을 보여주어야 합니다:
App: {appName}
Version: {version}
Max Users: {maxUsers}
Error: Config is read-only
Max Users: {maxUsers}예를 들어, 입력이 MyApp, 2.0, 100인 경우 출력은 다음과 같아야 합니다:
App: MyApp
Version: 2.0
Max Users: 100
Error: Config is read-only
Max Users: 100기억하세요: 프록시 패턴은 사용자가 상호작용하는 빈 테이블을 사용하며, 실제 데이터는 별도의 내부 테이블에 저장됩니다. __index 메타메소드는 데이터 테이블에서 값을 가져오고, __newindex는 모든 쓰기 시도를 가로채서 차단합니다!
치트 시트
__newindex 메타메소드는 테이블에 새로운 값을 할당하려는 시도를 가로챕니다. 모든 할당을 차단함으로써, 불변(읽기 전용) 객체를 생성할 수 있습니다:
local ImmutablePoint = {}
function ImmutablePoint.new(x, y)
local data = {x = x, y = y}
local proxy = {}
setmetatable(proxy, {
__index = data,
__newindex = function()
error("Cannot modify immutable object")
end
})
return proxy
end프록시 패턴(proxy pattern)은 사용자가 상호작용하는 빈 테이블(proxy)을 사용하며, 실제 데이터는 별도의 내부 테이블(data)에 저장됩니다:
__index는 읽기 시에data테이블에서 값을 가져옵니다.__newindex는 쓰기 시도를 가로채고 이를 차단합니다.
local p = ImmutablePoint.new(10, 20)
print(p.x) -- 10 (읽기 가능)
p.x = 50 -- Error: Cannot modify immutable object이 패턴은 설정 객체, 수학적 상수 또는 초기화 후 변경되지 않아야 하는 모든 데이터에 유용합니다.
직접 해보기
-- ImmutableConfig 모듈 가져오기
local ImmutableConfig = require('ImmutableConfig')
-- 입력값 읽기
local appName = io.read()
local version = io.read()
local maxUsers = tonumber(io.read())
-- TODO: ImmutableConfig.new()를 사용하여 설정 객체 생성하기
-- TODO: 다음 형식으로 세 가지 원본 값 모두 출력하기:
-- App: {appName}
-- Version: {version}
-- Max Users: {maxUsers}
-- TODO: maxUsers 필드 수정을 시도하기 (에러 메시지가 발생해야 함)
-- TODO: 변경되지 않았음을 증명하기 위해 maxUsers를 다시 출력하기
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.