博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
在lua中创建字段安全的对象
阅读量:7122 次
发布时间:2019-06-28

本文共 3300 字,大约阅读时间需要 11 分钟。

  lua萌新,刚刚学习和使用不到一个月。有不对的地方,还望各路大神不吝赐教。

  lua中可以用table来模拟对象,但table是可以任意增加键值的。在对象模拟中,暂且也叫它为字段(field)吧。如果在面向对象中,你定义了一个对象,可以在对象以外的地方随意改动这个对象的字段,访问不存在的字段,你想象一下这有多恐怖?比如你定义了一个Vector3{float x = 0; float y = 0; float z = 0;}  我在外面某处加一个float t = 1; 当你在创建并引用这对象的时候,你就懵逼了,t是什么鬼?又或者你new 一个对象 vector,然后去取一个值,本来里面没有 t 这个字段,vector.t 给你返回一个空值,你是不是又懵逼了?到底是里面有这个字段值为空,还是压根就没这个字段?嗯? 感觉太不可控了。

  那么,有没有办法让它可控一点呢?有的。利用元表的__index 和__newindex,具体如下代码:

local Vector3 = {}function Vector3:new()    local v3 =     {        x = 0,   -- Note:这个值不能为nil,不然找不到这个字段        y = 0,        z = 0,    }    setmetatable(v3, self)    self.__index =         function(self, key)            error("Vector3类型中没有定义字段:" .. key, 2)        end    self.__newindex =         function(self, key, value)            error("Vector3类型中没有定义字段:" .. key, 2)          end    return v3endlocal v  = Vector3:new()v.x = 2--v.t = 3print(v.x)print(v.y)--print(v.t)

上面的代码输出:

但当你尝试把v.t = 3 的注释去掉的话,就报错了:

尝试去掉print(v.t)  的注释的话,也会报错:

  这样就可以确保这个结构的安全,主要体现在不能在外部随意对它修改。

   --------------------2017.08.20更新

  下面是升级版本的,初始化的时候可以传入参数,为初始化提供了方便。还提供了一个ToString()方法。

 

local Vector3 = {}function Vector3:new(x0, y0, z0)    local v3 =     {        x = x0 or 0,        y = y0 or 0,        z = z0 or 0,        ToString = function(self)            return "(" .. self.x .. "," .. self.y .. "," .. self.z  .. ")"        end    }    setmetatable(v3, self)    self.__index =         function(self, key)            error("Vector3类型中没有定义字段:" .. key, 2)        end    self.__newindex =         function(self, key, value)            error("Vector3类型中没有定义字段:" .. key, 2)          end    return v3endlocal v  = Vector3:new(3, 3, 3)v.x = 2print(v.x)print(v.y)print("Vector3 v = " .. v:ToString())

  --------------------2017.08.22更新

  上面的方法依然会有问题,就是当给字段赋值为空的时候,相当于把字段删了,字段就消失了。不能再次访问或者赋值。下面是再次升级的版本:

 

local Vector3 = {}function Vector3:new(x0, y0, z0)    --合法字段和默认值    local v3_field =     {        x = 0,         y = 0,        z = 0,    }    --初始化字段    local v3 =     {        x = x0 or v3_field.x,        y = y0 or v3_field.y,        z = z0 or v3_field.z,    }    setmetatable(v3, self)    self.__tostring = function(self)            return "(" .. self.x .. "," .. self.y .. "," .. self.z  .. ")"        end    self.__index =         function(self, key)            local valid = false            for k, v in pairs(v3_field) do                 if key == k then                    valid = true                    result = rawget(v3, key) or v --如果值为空,返回v3_field中的默认值                    return result                end            end            if not valid then                error("Invalid field in Vector3: " .. key, 2)            end        end    self.__newindex =         function(self, key, value)            print("set newindex")            local valid = false            for k, v in ipairs(v3_field) do                 if key == k then                    valid = true                    rawset(v3, key, value)                    return                end            end            if not valid then                error("Invalid field in Vector3: " .. key, 2)            end          end    return v3endlocal v  = Vector3:new(3, 3, 3)v.x = 2print(v.x)v.y = nilprint(v.y)print("Vector3 v = " .. tostring(v))

 

输出为:

这样即使是字段被赋值为nil,依然可以访问并重新赋值。

 

转载于:https://www.cnblogs.com/yougoo/p/7398194.html

你可能感兴趣的文章
写代码要注意的小细节
查看>>
ServletFileUpload使用方法
查看>>
JXL操作Excel
查看>>
2015年最受关注的8项IT技能
查看>>
github上的版本和本地版本冲突的解决方法
查看>>
apache和tomcat区别
查看>>
yii2有了一个js端的urlManager扩展了
查看>>
PHP命令行下的世界
查看>>
Docker多容器连接-以Nginx+PHP为例
查看>>
node.js http.serverResponse
查看>>
让我们聊聊脑裂这事情
查看>>
入侵检测 - AIDE高级入侵检测平台
查看>>
Getting unknown property: yii\db\ActiveQuery::name
查看>>
CentOS 6.5 双网卡配置一个上外网一个接局域网
查看>>
linux手动释放cached内存
查看>>
链表的基本操作
查看>>
arm-2009q1-203-arm-none-linux-gnueabi 安装
查看>>
Spring中的统一异常处理方式
查看>>
wemall 2.0 beta 公测版
查看>>
Mac别名以及自定义命令
查看>>