在lua中创建字段安全的对象
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中创建字段安全的对象的更多相关文章
- Java中创建(实例化)对象的五种方式
Java中创建(实例化)对象的五种方式1.用new语句创建对象,这是最常见的创建对象的方法. 2.通过工厂方法返回对象,如:String str = String.valueOf(23); 3.运用反 ...
- 在Spring应用中创建全局获取ApplicationContext对象
在Spring应用中创建全局获取ApplicationContext对象 1.需要创建一个类,实现接口ApplicationContextAware的setApplicationContext方法. ...
- 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 ...
- 按要求编写Java应用程序。 (1)创建一个叫做机动车的类: 属性:车牌号(String),车速(int),载重量(double) 功能:加速(车速自增)、减速(车速自减)、修改车牌号,查询车的载重量。 编写两个构造方法:一个没有形参,在方法中将车牌号设置“XX1234”,速 度设置为100,载重量设置为100;另一个能为对象的所有属性赋值; (2)创建主类: 在主类中创建两个机动车对象。 创建第
package com.hanqi.test; public class jidongche { private String chepaihao;//车牌号 private int speed;// ...
- 编写Java应用程序。首先,定义一个Print类,它有一个方法void output(int x),如果x的值是1,在控制台打印出大写的英文字母表;如果x的值是2,在 控制台打印出小写的英文字母表。其次,再定义一个主类——TestClass,在主类 的main方法中创建Print类的对象,使用这个对象调用方法output ()来打印出大 小写英文字母表。
package zuoye; public class print1 { String a="abcdefghigklmnopqrstuvwxyz"; String B=" ...
- (1)创建一个叫做机动车的类: 属性:车牌号(String),车速(int),载重量(double) 功能:加速(车速自增)、减速(车速自减)、修改车牌号,查询车的载重量。 编写两个构造方法:一个没有形参,在方法中将车牌号设置“XX1234”,速 度设置为100,载重量设置为100;另一个能为对象的所有属性赋值; (2)创建主类: 在主类中创建两个机动车对象。
package a; public class Jidongche { private String chepaihao; private int chesu; private double zaiz ...
- 首先,定义一个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 ...
- .编写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 ...
- 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 ...
随机推荐
- 2018-02-27 "Literate Programming"一书摘记之一
书到后才发现是Knuth的论文集, 第一篇就在网上: Computer programming as an art (1974). 其中"Taste and Style"(品味和风 ...
- 【读书笔记】iOS-手势识别
一,事件处理机制 事件是当用户手指触及屏幕,或地屏幕上滑动,或摇晃设备等时候,系统不断地把这些事件通过消息发送给应用程序对象.在iOS设备中能够捕获的事件有3种:触摸事件,移动事件和多媒体远程控制事件 ...
- pip install 报错
问题描述,在使用pip安装django相关软件包时,提示错误如下: [root@test4 install]# pip install django==1.6 Downloading/unpackin ...
- Tomcat 部署外部系统
/usr/local/tomcat/conf/Catalina/localhost/resource.xml <?xml version='1.0' encoding='utf-8' ?> ...
- IDEA错误:Failed to start end point associated with ProtocolHandler [http-nio-9999] java.net.BindException: Address already in use: bind
日志显示进程端口已被占用,首先需要的是查询什么进程占用了当前的9999端口. 1.win+R输入cmd进入命令界面: 2.输入命令 netstat -ano|findstr "端口号&qu ...
- JAVA 设计模式遵循的六大基本准则
JAVA 设计模式遵循的六大基本准则 一.单一职责原则:(Single Responsibility Pinciple) 一个类只负责一项职责. 当超过一项职责需要负责时,需要增加新的类来负责新的职 ...
- Android、IOS文字居中偏离的解决方案
前言 移动端开发,经常会遇到的问题,就是文字居中.一般都只能往css方向去fix这个问题. 自己以前也用过position:relative;top:-*px的方式去解决.
- Spring Boot 技术总结
Spring Boot(一):入门篇 Spring Boot(二):Web 综合开发 Spring Boot(三):Spring Boot 中 Redis 的使用 Spring Boot(四):Thy ...
- linux networking
ip route解读 default via 192.168.1.1 dev wlan0 dev wlan0 proto kernel scope link src 192.168.1.100 htt ...
- [20171225]RMAN-06808: SECTION SIZE cannot be used when piece limit is in effect.txt
[20171225]RMAN-06808: SECTION SIZE cannot be used when piece limit is in effect.txt --//朋友拿我的一些例子来测试 ...