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 = , -- Note:这个值不能为nil,不然找不到这个字段
y = ,
z = ,
} setmetatable(v3, self)
self.__index =
function(self, key)
error("Vector3类型中没有定义字段:" .. key, )
end
self.__newindex =
function(self, key, value)
error("Vector3类型中没有定义字段:" .. key, )
end
return v3
end local v = Vector3:new()
v.x =
--v.t = 3
print(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 ,
y = y0 or ,
z = z0 or , ToString = function(self)
return "(" .. self.x .. "," .. self.y .. "," .. self.z .. ")"
end
} setmetatable(v3, self)
self.__index =
function(self, key)
error("Vector3类型中没有定义字段:" .. key, )
end
self.__newindex =
function(self, key, value)
error("Vector3类型中没有定义字段:" .. key, )
end
return v3
end local v = Vector3:new(, , )
v.x =
print(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 = ,
y = ,
z = ,
}
--初始化字段
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, )
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, )
end
end
return v3
end local v = Vector3:new(, , )
v.x =
print(v.x)
v.y = nil
print(v.y)
print("Vector3 v = " .. tostring(v))

输出为:

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

在lua中创建字段安全的对象的更多相关文章

  1. Java中创建(实例化)对象的五种方式

    Java中创建(实例化)对象的五种方式1.用new语句创建对象,这是最常见的创建对象的方法. 2.通过工厂方法返回对象,如:String str = String.valueOf(23); 3.运用反 ...

  2. 在Spring应用中创建全局获取ApplicationContext对象

    在Spring应用中创建全局获取ApplicationContext对象 1.需要创建一个类,实现接口ApplicationContextAware的setApplicationContext方法. ...

  3. 11.按要求编写Java应用程序。 (1)创建一个叫做机动车的类: 属性:车牌号(String),车速(int),载重量(double) 功能:加速(车速自增)、减速(车速自减)、修改车牌号,查询车的载重量。 编写两个构造方法:一个没有形参,在方法中将车牌号设置“XX1234”,速 度设置为100,载重量设置为100;另 一个能为对象的所有属性赋值; (2)创建主类: 在主类中创建两个机动车对象。

    package java1; public class Che { //属性 public String nub; public int speed; public double weight ; C ...

  4. 按要求编写Java应用程序。 (1)创建一个叫做机动车的类: 属性:车牌号(String),车速(int),载重量(double) 功能:加速(车速自增)、减速(车速自减)、修改车牌号,查询车的载重量。 编写两个构造方法:一个没有形参,在方法中将车牌号设置“XX1234”,速 度设置为100,载重量设置为100;另一个能为对象的所有属性赋值; (2)创建主类: 在主类中创建两个机动车对象。 创建第

    package com.hanqi.test; public class jidongche { private String chepaihao;//车牌号 private int speed;// ...

  5. 编写Java应用程序。首先,定义一个Print类,它有一个方法void output(int x),如果x的值是1,在控制台打印出大写的英文字母表;如果x的值是2,在 控制台打印出小写的英文字母表。其次,再定义一个主类——TestClass,在主类 的main方法中创建Print类的对象,使用这个对象调用方法output ()来打印出大 小写英文字母表。

    package zuoye; public class print1 { String a="abcdefghigklmnopqrstuvwxyz"; String B=" ...

  6. (1)创建一个叫做机动车的类: 属性:车牌号(String),车速(int),载重量(double) 功能:加速(车速自增)、减速(车速自减)、修改车牌号,查询车的载重量。 编写两个构造方法:一个没有形参,在方法中将车牌号设置“XX1234”,速 度设置为100,载重量设置为100;另一个能为对象的所有属性赋值; (2)创建主类: 在主类中创建两个机动车对象。

    package a; public class Jidongche { private String chepaihao; private int chesu; private double zaiz ...

  7. 首先,定义一个Print类,它有一个方法void output(int x),如果x的值是1,在控制台打印出大写的英文字母表;如果x的值是2,在 控制台打印出小写的英文字母表。其次,再定义一个主类——TestClass,在主类 的main方法中创建Print类的对象,使用这个对象调用方法output ()来打印出大 小写英文字母表。

    package lianxi; public class Print_1 { int x; Print_1(int x) { this.x = x; } void outPut() { String ...

  8. .编写Java应用程序。首先,定义一个Print类,它有一个方法void output(int x),如果x的值是1,在控制台打印出大写的英文字母表;如果x的值是2,在 控制台打印出小写的英文字母表。其次,再定义一个主类——TestClass,在主类 的main方法中创建Print类的对象,使用这个对象调用方法output ()来打印出大 小写英文字母表。

    package com.homework.zw; //类Print部分 public class Print1 { int x; void output() { if(x==1) { for(int ...

  9. 7.编写Java应用程序。首先,定义一个Print类,它有一个方法void output(int x),如果x的值是1,在控制台打印出大写的英文字母表;如果x的值是2,在 控制台打印出小写的英文字母表。其次,再定义一个主类——TestClass,在主类 的main方法中创建Print类的对象,使用这个对象调用方法output ()来打印出大 小写英文字母表。

    package com.bao; public class Print1 { int x; void output() { if(x==1) { System.out.println("AB ...

随机推荐

  1. 【读书笔记】iOS-xib,自动布局(二)

    我们紧接着上面的文章来写. 一,此时没有选择自动布局的时候 . 二,选中Use Auto Layout.如下图所示. 三,自动布局与不自动布局最明显的区别是右下角多了4个按钮.如图所示. 四,设置On ...

  2. 【读书笔记】iOS-个人开发者与企业开发者的区别

    个人开发者与企业开发者的一个主要的区别在于独立开发者授权描述文件必须列出具体的设备.另一个不同就是开发者账户最多使用100台设备,而企业则可以让苹果公司生成未锁定到特定设备并可以安装到任何设备上的授权 ...

  3. Sharepoint 2013 Gatherer 数据库的架构版本低于此 Gatherer 应用程序支持的向后兼容的最低架构版本

    管理中心 ->升级和迁移 ->查看数据库状态 解决方法: 开始-运行(以管理员身份运行),输入如下命令. cd  C:\Program Files\Common Files\Microso ...

  4. 为什么 C# 比 C++ 编译快那么多

    Go 我不懂,下面以 C++ 和 C# 对比来说明为什么 C++ 编译慢和 C# 编译快. C 和 C++ 文件的编译经过几个主要步骤: 处理续行符处理(“\”)之类的杂事 词法分析,解析出 toke ...

  5. Android学习笔记----Java中的字符串比较

    用习惯了C#.C++,在做字符串比较时想当然地使用如下语句: string str1 = "abcd", str2 = "abcd"; if(str1==str ...

  6. 洗礼灵魂,修炼python(49)--巩固篇—包

    包(Package) 这个其实前面也说过的,不过同模块一样,没有具体的解析 1.什么是包 在创建许许多多模块后,我们可能希望将某些功能相近的文件组织在同一文件夹下,那么此文件夹(目录)即为包,文件夹( ...

  7. SqlServer索引页损坏恢复

    问题背景 运维操作失误,在没有正常关闭sqlserver的情况下,将服务器关闭了,重启后某些表损坏(应该是某些页损坏了,没有损坏的页还能访问到数据,但是访问损坏了的页就有问题),目前数据库只有4.20 ...

  8. owncloud 实现私有云进行多端文件同步

    研究生生涯开始了,事情逐渐多了起来.都没时间写博客了... 开学实验室配了台电脑,我把主机装上了Fedora 作为我的服务器.平时有些实验室的材料,经常几个电脑一起看,使用U盘拷来拷去很是麻烦.今天重 ...

  9. Python描述符 (descriptor) 详解

    1.什么是描述符? python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问.这些方法有 __get__(), __set__(), 和__delete__().如 ...

  10. 【PAT】B1074 宇宙无敌加法器(20 分)

    打一开始做就听人说这个难,吓得我把它放到了最后做,不过如此嘛. 这里说说样例的坑点 1.最后结果可能高位有0:例如样例结果07201 2.结果会进位, 3.有可能结果是0,(此处取决于你的输出方式) ...