Lua中的值类型
空值 nil
lua中的空值与其他语言null类似,用关键字nil表示。
数字 number(double)
lua中的数字均以双精度浮点数存放,不存在整数和浮点数的区别,不过在lua的语法说明里面也明确表示,编译时时可以用整数和单精度浮点数表示的。
字符串 string
lua中的字符串与其他语言类似,并且在lua里,没有字符型的数据,单个字符也是作为字符串存放的。
布尔 bool
lua中的布尔值与其他语言类似,但是在lua中,空字符串和0都是true,这在之后的逻辑表达式里提供了很大的方便。
function
在lua里,函数实际上是作为一种值存在,可以作为变量存取,可以作为其他函数的参数,甚至作为返回值。
userdata
这个个人理解为一种指针,在与其他语言交换数据时,实际上交换的就是这样一个东西。在使用Unity的过程中,经常碰到物件销毁后判断是否为空的情况,而Unity销毁物件后,lua里的这种“指针”仍然指向那个物体,所以这种情况必须使用GameObject:Equals(nil)
这样的方式去判断其是否为空,以后会有详细的说明。
Lua中的结构类型
Table
在Lua里,Table是唯一的一种数据结构,存放数据的方式是键值对key = value
。强大,方便,容易理解。其他语言中的数据结构都可以通过Table来实现。之后的面向对象也是通过Table去模拟类的行为。
同时,键值对的直观性也让Lua语言有很好的可读性。越来越多的人开始使用Lua作为配置文件使用。
数组
用Table模拟数组,只需要在Table里按顺序放入value就行,key的值自动从1开始。
array = { 1, 3, 5, 7, 9 };
-- 想要得到数组长度,可以使用下面的方法
print(#array, table.getn(array)); --> 5 5
-- 数组的下标从1开始
print(array[0]); --> nil;
print(array[1]); --> 1;
print(array[5]); --> 9;
不过这样模拟的数组不会有越界报错,只可能出现空值(nil)报错,因为在Lua里变量不用事先声明,而这样的数组只是一连串的变量而已。
array = { 1, 3, 5, 7, 9 };
print(array[10]); --> nil
array[9] = 0;
print(array[9]); --> 0
print(array[10]..""); --> error:attempt to concatenate a nil value
运行上面的例子可以发现,在使用array的过程中没有出现任何异常错误,甚至可以赋值!但是当你把它作为参数用在别的地方,而你之前又未对它进行赋值时,就会出现错误了。这个问题当然也是可以通过设计去解决的,这在以后研究模拟面向对象时会讲解。
哈希表
Table和哈希表都是一种通过索引去访问的键值对,几乎是等价的。
hashmap = {};
function Print() -- 遍历输出表的内容
local str = "";
for k, v in pairs(hashmap) do
str = str..k..": "..v..";\t"
end
print(str);
end
hashmap[0] = "a"; -- 直接通过索引加入值
table.insert(hashmap, "b"); -- table.insert()可以在表中插入值,不指定插入位置,会自动放在表最后
hashmap.a = "c"; -- 使用点号也可以通过变量名索引
Print(); --> 0: a; 1: b; a: c;
-- 删除元素直接让键值对中的value为nil就可以
hashmap[0] = nil;
table.remove(hashmap, 1);
hashmap.a = nil;
Print(); -->
以上两种是目前想到的,不需要任何设计就可以实现的两种结构(实际上是通过Lua访问Table成员的方式去模拟)。
面向对象的类
用Lua去模拟面向对象的类,需要掌握很多相关的语法知识,其中比较晦涩难懂的,就是元表metatable和__index元方法,这些会在以后进行详细的整理。
这里想事先说明的,不管是怎么模拟的面向对象,Lua的基本语法里没有私有性,没有静态动态,没有继承派生,变量不需要事先声明,也没有规定你必须有构造和析构方法,所有的一切,都是通过设计去模拟面向对象的各种特性。Lua的简单灵活是它的优势,口头规定的规则不能保证程序的稳定性。
Class = {
className = "Class";
name;
value;
};
Class.__index = Class
function Class.New(name, value)
local self = {};
setmetatable(self, Class);
self.name = name;
self.value = value;
return self;
end
function Class:SetValue(value)
self.value = value;
end
function Class:Print()
print(self.name, self.value);
end
obj1 = Class.New("obj1", 1);
obj2 = Class.New("obj2", 2);
obj1:Print(); --> obj1 1
obj2:Print(); --> obj2 2
obj1:SetValue(3);
obj1:Print(); --> obj1 3
obj2:Print(); --> obj2 2
以上是一个简单的面向对象例子,理解起来应该不难。在之后的文章中,我会整理出几个重要的设计,来实现一些常用的功能。