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. CSS效果:CSS实用技巧制作三角形以及箭头效果

    实现如图所示的三角形图标: html代码如下: <div class="arrow-up"></div> <div class="arrow ...

  2. [笔记] imooc《JavaScript深入浅出》对象与函数

    懒得做草稿了,习惯md也懒得扔印象笔记 主要是之前没去接触这一部分,就随手记下来了 创建对象的方法 对象字面量 new构造器/原型链 Object.create() 属性操作 属性读写(以及读写异常. ...

  3. vue-cli脚手架之package.json

    package.json文件配置及其含义,这个是vue-cli自动生成的文件,先贴一张代码及其含义: { "name": "secondproject",//模 ...

  4. [20171120]理解v$session的state字段(11G).txt

    [20171120]理解v$session的state字段(11G).txt --//https://blogs.oracle.com/database4cn/vsession-%e4%bd%a0%e ...

  5. JMeter—断言(十一)

    参考<全栈性能测试修炼宝典JMeter实战>第六章 JMeter 元件详解中第六节断言断言用来对服务器的响应数据做验证,常用的断言是响应断言,支持正则表达式. 一.BeanShell As ...

  6. 03-12_MBean层次结构

    本文重点: Mbeans层次结构与WLST关系介绍 WebLogic Mbeans的类型 weblogic服务器的MBeans生命周期             Mbeans层次结构与WLST关系介绍: ...

  7. plsql备份表---只是表---不包含表数据

    写这个的同时还在备份,表的数据进度很慢,数据太大了. 用的工具是plsql 导出表:点击    tool工具  ---> export user object 导出用户目标  ----> ...

  8. fedora 28 , firewalld 防火墙控制,firewall-cmd 管理防火墙规则

    今天,在使用fedora时,需要修改防火墙规则,一时间忘记了命令是什么,这里进行记录一下. 目前 fedora 28/ centos 7 使用 firewalld 作为防火墙软件:下面我就怎么简单管理 ...

  9. [HDFS_add_1] HDFS 启动过程分析

    0. 说明 HDFS 文件概念 && HDFS 启动过程分析 1. HDFS 文件概念 [1.1 NameNode 职能] 存储文件类型.大小.权限.路径等等元数据 通过 edits( ...

  10. PLSQL操作Oracle创建用户和表

    1.打开PLSQL,填写用户名和密码(初始有两个用户sys和system,密码是自己安装oracle数据库时定的),Database选择ORCL(默认数据库,oracle中创建的用户就像是mysql中 ...