2015-02-04 5 views
3

예를 썼습니다.루아에서 읽기 전용 테이블을 어떻게 구현할 수 있습니까?

function readOnly(t) 
     local newTable = {} 
     local metaTable = {} 
     metaTable.__index = t 
     metaTable.__newindex = function(tbl, key, value) error("Data cannot be changed!") end 
     setmetatable(newTable, metaTable) 
     return newTable 
    end 

local tbl = { 
    sex = { 
     male = 1, 
     female = 1, 
    }, 
    identity = { 
     police = 1, 
     student = 2, 
     doctor = { 
      physician = 1, 
      oculist = 2, 
     } 
    } 
} 

local hold = readOnly(tbl) 
print(hold.sex) 
hold.sex = 2 --error 

그것은 I 테이블 「TBL」의 필드에 대한 액세스를 제공 할 수 있지만, 동시에 I 필드와 관련된 값을 변경할 수 있다는 것을 의미한다.

이제 문제는 모든 중첩 테이블이이 읽기 전용 속성을 소유하도록하려는 것입니다. 어떻게 "readOnly"메소드를 향상시킬 수 있습니까?

답변

5

readOnly 함수를 재귀 적으로 내부 테이블 필드에도 적용하면됩니다. __index 메타 메서드에서 온 액세스를 수행 할 수 있습니다. 또한 생성 한 읽기 전용 프록시 테이블을 캐시해야합니다. 그렇지 않으면 내부 테이블 (예 : hold.sex)에 대한 읽기 액세스로 인해 새 프록시 테이블이 만들어집니다.

-- remember mappings from original table to proxy table 
local proxies = setmetatable({}, { __mode = "k" }) 

function readOnly(t) 
    if type(t) == "table" then 
    -- check whether we already have a readonly proxy for this table 
    local p = proxies[ t ] 
    if not p then 
     -- create new proxy table for t 
     p = setmetatable({}, { 
     __index = function(_, k) 
      -- apply `readonly` recursively to field `t[k]` 
      return readOnly(t[ k ]) 
     end, 
     __newindex = function() 
      error("table is readonly", 2) 
     end, 
     }) 
     proxies[ t ] = p 
    end 
    return p 
    else 
    -- non-tables are returned as is 
    return t 
    end 
end