严格结构体 |
|
可以这样声明一个 '结构体'
struct.Alice { x = 1; y = 2; }
并像这样实例化
a = Alice {x = 10, y = 20}
或者
b = Alice {x = 10} -- y will be set to 2
任何尝试访问 a 和 b 的未知字段的操作都会导致错误,例如 a.z = 1
或 print(b.zz)
,甚至 Alice{z = 4}
。
因此,这带来了两点好处
Alice
,而不是 '包含 x 和 y 为数字的表格'。
更强的类型化也意味着可以抛出特定于类型的断言。
对 __tostring
的简单重载也会为您提供特定于类型的字符串表示,例如 'Alice #23',用于调试目的。
可以使用合适的代理表格来强制对字段赋值进行动态类型检查,但这当然会带来运行时成本。
-- struct.lua --- defining a struct constructor --- local struct_mt = { -- instances can be created by calling the struct object __call = function(s,t) local obj = t or {} -- pass it a table (or nothing) local fields = s._fields -- attempt to set a non-existent field in ctor? for k,v in pairs(obj) do if not fields[k] then s._error_nf(nil,k) end end -- fill in any default values if not supplied for k,v in pairs(fields) do if not obj[k] then obj[k] = v end end setmetatable(obj,s._mt) return obj end; } -- creating a new struct triggered by struct.STRUCTNAME struct = setmetatable({},{ __index = function(tbl,sname) -- so we create a new struct object with a name local s = {_name = sname} -- and put the struct in the enclosing context _G[sname] = s -- the not-found error s._error_nf = function (tbl,key) error("field '"..key.."' is not in "..s._name) end -- reading or writing an undefined field of this struct is an error s._mt = { _name = s._name; __index = s._error_nf; __newindex = s._error_nf; } -- the struct has a ctor setmetatable(s,struct_mt) -- return a function that sets the struct's fields return function(t) s._fields = t end end })