Created
October 24, 2025 16:42
-
-
Save aiya000/58ea5d3cc8b753a075b4a9600f8a9608 to your computer and use it in GitHub Desktop.
How to create freezed table in Lua
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- readonly() {{{ | |
| ---Creates a readonly table | |
| ---@generic K, V | |
| ---@param x table<K, V> | |
| ---@return table<K, V> --But readonly | |
| local function readonly(x) | |
| return setmetatable({}, { | |
| __index = x, | |
| __newindex = function(_, key, value) | |
| error(('The table is readonly. { key = %s, value = %s }'):format(key, tostring(value))) | |
| end, | |
| __metatable = false | |
| }) | |
| end | |
| local function test_readonly() | |
| -- Good case | |
| local x = readonly({ | |
| a = 10, | |
| }) | |
| local ok1, result1 = pcall(function() | |
| x.a = 20 | |
| end) | |
| -- false | |
| vim.notify('readonly() - 1: Should be false => ' .. vim.inspect({ ok1, result1 }), vim.log.levels.INFO) | |
| -- Bad case | |
| local y = readonly({ | |
| a = { | |
| b = 10, | |
| }, | |
| }) | |
| local ok2, result2 = pcall(function() | |
| y.a.b = 20 | |
| end) | |
| -- true | |
| vim.notify('readonly() - 2: Should be true => ' .. vim.inspect({ ok2, result2 }), vim.log.levels.INFO) | |
| end | |
| test_readonly() | |
| -- }}} | |
| --- deep_readonly() {{{ | |
| ---Creates a deeply readonly table | |
| ---@generic K, V | |
| ---@param x table<K, V> | |
| ---@return table<K, V> --But deeply readonly | |
| local function deep_readonly(x) | |
| ---@generic K, V | |
| ---@param a table<K, V> | |
| ---@return table<K, V> | |
| local function create_deep_readonly(a) | |
| return setmetatable({}, { | |
| __index = deep_readonly(a), | |
| __newindex = function(_, key, value) | |
| error(('The table is readonly. { key = %s, value = %s }'):format(key, tostring(value))) | |
| end, | |
| __metatable = false | |
| }) | |
| end | |
| local result = {} | |
| for key, value in pairs(x) do | |
| if type(value) == 'table' then | |
| result[key] = create_deep_readonly(value) | |
| else | |
| result[key] = value | |
| end | |
| end | |
| return readonly(result) | |
| end | |
| local function test_deep_readonly() | |
| -- Good case | |
| local x = deep_readonly({ | |
| a = 10, | |
| }) | |
| local ok1, result1 = pcall(function() | |
| x.a = 20 | |
| end) | |
| -- false | |
| vim.notify('deep_readonly() - 1: Should be false => ' .. vim.inspect({ ok1, result1 }), vim.log.levels.INFO) | |
| -- Also, Good case | |
| local y = deep_readonly({ | |
| a = { | |
| b = 10, | |
| }, | |
| }) | |
| local ok2, result2 = pcall(function() | |
| y.a.b = 20 | |
| end) | |
| -- false | |
| vim.notify('deep_readonly() - 2: Should be false => ' .. vim.inspect({ ok2, result2 }), vim.log.levels.INFO) | |
| end | |
| test_deep_readonly() | |
| -- }}} | |
| -- NOTE: This is useless... [[ | |
| -- readonly_value() {{{ | |
| ---Simular to `readonly()` | |
| ---```lua | |
| ----- These are same: | |
| ---local x = readonly({ value = 10 }) | |
| ---local y = readonly_value(10) | |
| ---``` | |
| ---@generic T | |
| ---@param value T | |
| ---@return { value: T } | |
| local function readonly_value(value) | |
| return readonly({ | |
| value = value, | |
| }) | |
| end | |
| local function test_readonly_value() | |
| local x = readonly_value(10) | |
| local ok1, result1 = pcall(function() | |
| x = 20 | |
| end) | |
| vim.notify('readonly_value(): Should be false => ' .. vim.inspect({ ok1, result1 }), vim.log.levels.INFO) | |
| end | |
| -- Commented out because this one does fails as a matter of course. | |
| -- test_readonly_value() | |
| -- }}} | |
| -- ]] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
readonly_value()はconst変数を作れるようにしようと思って、途中で生み出した成果(成果ではないかも)もしかしたら以下で(全てがconstになることを無視すれば)モジュールconst変数ができるかも