Menu
Coddy logo textTech

읽기 전용 테이블

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와 상호작용합니다.

읽을 때 __indexdata에서 값을 가져옵니다. 쓸 때는 대신 __newindex가 트리거되며, 이를 차단합니다:

local p = ImmutablePoint.new(10, 20)
print(p.x)  -- 10 (읽기 가능)
p.x = 50    -- 오류: 불변 객체는 수정할 수 없습니다

이 패턴은 설정 객체, 수학적 상수 또는 초기화 후 절대 변경되지 않아야 하는 모든 데이터에 유용합니다. 객체는 완전히 읽기 가능한 상태로 유지되지만, 수정할 수는 없습니다.

challenge icon

챌린지

쉬움

읽기 전용 설정 객체를 생성하는 ImmutableConfig 클래스를 만들어 봅시다! 이 설정 객체는 생성된 후 설정을 읽을 수는 있지만, 수정하려는 모든 시도는 완전히 차단해야 합니다.

코드는 다음 두 개의 파일로 구성됩니다:

  • ImmutableConfig.lua: 고정된 설정 객체를 생성하는 모듈을 만듭니다. .new(appName, version, maxUsers) 함수는 이 세 가지 값을 내부적으로 저장한 다음, 모든 필드를 읽을 수는 있지만 수정은 방지하는 프록시 테이블을 반환해야 합니다. 누군가 값을 변경하려고 하면 실제 에러를 발생시키는 대신 Error: Config is read-only를 출력해야 합니다.
  • main.lua: ImmutableConfig를 실제로 실행해 봅니다! 설정 값으로 사용할 세 개의 입력을 읽고, 설정 객체를 생성한 후, 다음을 통해 올바르게 작동하는지 증명하세요:
    • 세 가지 원본 값을 모두 출력합니다.
    • maxUsers 필드 수정을 시도합니다 (이때 에러 메시지가 출력되어야 합니다).
    • maxUsers를 다시 출력하여 실제로 변경되지 않았음을 증명합니다.

세 가지 입력을 받게 됩니다:

  1. 애플리케이션 이름 (문자열)
  2. 버전 (문자열)
  3. 최대 사용자 수 (숫자)

출력은 설정 값, 수정 시도 시 발생하는 에러, 그리고 값이 변경되지 않았음을 확인하는 내용을 보여주어야 합니다:

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를 다시 출력하기
quiz icon실력 점검

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

Object Oriented Programming의 모든 레슨