一. 一些小的注意点
- 条件判断
num = 0
if num then print("true")
else print("false")
end
-- 输出结果为:true
-
只有在
num = nil和num = false时,才会打印false -
**num = 0时也为true **
-
不等于
if num ~= 10 then print(num) --和C的不等于写法不一样
end
- 三目运算
r = a and b or c -->这样的写法存在一个BUG,当b=nil时, 返回c
r= (a and {b} or {c})[1] -->这样才是安全的写法
- for
for i=0,10 do --i范围[0,10]
print(i)
end
for i=10,0,-1 --i范围[10,0]
print(i)
end
- 闭包&匿名函数
function adder(x)
return function (y) return x + y end
end
a1 = adder(9)
a2 = adder(36)
print(a1(16)) --25
print(a2(64)) --100
--这些也是等价的:
local function g(x) return math.sin(x) end
local g
g = function (x) return math.sin(x) end
- 多返回值, 没用到的会被丢掉
x, y, z = 1, 2, 3, 4 --x=1,y=2,z=3,4被丢掉
function bar(a, b, c)
print(a, b, c)
return 4, 8, 15, 16, 23, 42
end
x, y = bar('zaphod') --print "zaphod nil nil"
-- 现在 x = 4, y = 8, 而值15..42被丢弃
- 变长参数
function add(...)
local s = 0
for i,v in ipairs{...} do
s = s + v
end
return s
end
print(add(3,4,10,25,12)) -- 54
- 字符串与数字
print("10" + 1) -- 11, 会自动转为数字相加
print("hello" + 1) -- 错误
print(11 ..22) -- 1122, 注意,数字后面要跟空格再跟".", 否则会认为是小数点
- 全局变量_G
所有的全局变量都是放在__G表里
for v in pairs(_G) do print(v) end
val = 10
print(_G['val']) -- 10
二. 基础数据类型
共8种:
- nil
- bool
- number
- string
- table
- userdata
- function
- thread
三. table
lua的唯一数据结构, 非顺序存储
- 语法格式
t={
[2]="v1",
[3]=6,
'v2',
idx3='v3',
['hello']=5,
"v4"
}
print(t[1]) -- v2
print(t[2]) -- v4
print(t[3]) -- 6
print(t.idx3) -- v3
print(t["idx3"]) -- v3
print(t['hello']) -- 5
print(t.hello) -- 5
用中括号括起来,是索引下标 不用中括号,默认是字符串索引
3.1 基础
- "#"号,求table长度, 下标必须从1开始, 到第一个自增不为1时结束
tbl = {[1] = 1, [2] = 2, [3] = 3}
print(#(tbl)) -- 3
tbl = {[1] = 1, [2] = 2, [6] = 6}
print(#(tbl)) -- 2
tbl = {['a'] = 1, [2] = 2, [3] = 6}
print(#(tbl)) -- 0
- table.maxn(), 获取整数下标的最大值. 无法获取字符串下标
tbl = {[1] = 1, [2] = 2, [3] = 3}
print(table.maxn(tbl)) -- 3
tbl = {[6] = 6, [1] = 1, [2] = 2}
print(table.maxn(tbl)) -- 6
tbl = {["a"] = 1, ["b"] = 2, ["c"] = 3}
print(table.maxn(tbl)) -- 0
print(#(tbl)) -- 0
3.2 table遍历
for key, value in pairs(tbl) do
XXX
end
-- ipairs必须是table下标从1开始,而且每次自增1, 否则遍历会结束
for key, value in ipairs(tbl) do
XXX
end
for i=1, #(tbl) do
XXX
end
for i=1, table.maxn(tbl) do
XXX
end
四. 类
lua是函数式编程, 没有类. 我们的类是一个表,它定义了各种属性和方法。 我们的实例也是一个表 然后我们类作为一个元表设置到实例上,并设置类的__index值为自身
4.1 metatable和metamethod
| 运算符 | metamethod | 描述 |
|---|---|---|
| + | __add(a,b) | 加 |
| - | __sub | 减 |
| * | __mul | 乘 |
| / | __div | 除 |
| % | __mod | 取模 |
| __pow | N次方 | |
| == | __eq | 等于 |
| <= | __le | 小于等于 |
| < | __lt | 小于 |
| ~=, >, >= | 无 | a~=b表示为not(a==b),a>b表示为b<a |
| __concat | 字符串连接 | |
| __tostring(tbl) | 转字符串 | |
| __index(tbl,key) | 当访问table不存在的域时会调用 | |
| __newindex(tbl,key,val) | 对table中不存在的域赋值时调用 |
4.2 语法糖
Person = {name="这个人很懒"}
-- 正常写法
Person.talk = function(self, words)
print(self.name.."说:"..words)
end
--下面写法与上面等价
function Person.talk(self, words)
print(self.name.."说:"..words)
end
--下面写法与上面等价
function Person:talk(words)
print(self.name.."说:"..words)
end
--下面两句等价
Person:talk("你好")
Person.talk(Person, "你好")
####4.3 类实现
- 一个简单的类
Class = {}
Class.__index = Class
--构造函数
function Class:new(x,y)
local temp = {}
setmetatable(temp, Class)
temp.x = x
temp.y = y
return temp
end
function Class:test()
print(self.x,self.y)
end
-- 点调用,需要传递this指针
object = Class.new(object,10,20)
object:test() -- 10 20
--下面的冒号调用与上面点调用等效
object = Class:new(10,20)
object:test() -- 10 20
- 继承
其实就是表与与的关联, 一个表找不到相应字段, 会去关联的表中查找
A = {}
function A:new(o)
o = {}
setmetatable(o,self)
self.__index = self
return o
end
function A:funName()
print('A')
end
--B继承A
B = A:new()
s = B:new()
function B:funName()
print('B')
end
s.funName() -- B
- 私有成员
使用闭包函数, 将成员存储在闭包的upvalue中 创建对象, 就是返回一堆闭包的集合
function new(name, age)
local inner = {mName = name, mAge = age}
local _setName = function (name)
inner.mName = name
end
local _setAge = function (age)
inner.mAge = age
end
local _getName = function () return inner.mName end
local _getAge = function () return inner.mAge end
return {setName = _setName, setAge = _setAge, getName = _getName, getAge = _getAge}
end
----
obj = new("张三", 25)
print(obj.getName()) --> 张三
print(obj.getAge()) --> 25
----
obj.setName("李四")
obj.setAge(18)
print(obj.getName()) --> 李四
print(obj.getAge()) --> 18
五. 闭包
即内嵌函数
六. 协同
与线程的区别点
- 任意时刻只能运行一个协同程序
- 正在运行的协同程序, 只有显示suspend时, 他的执行才会暂停
- 简单例子
co = coroutine.create(function () print("hi") end)
print(co) -- thread: 0x8071d98
print(coroutine.status(co)) -- suspended,协同被创建时, 默认是挂起的
coroutine.resume(co) -- hi
print(coroutine.status(co)) -- dead
- 挂起(yield)
co = coroutine.create(function ()
for i=1,5 do
print("co", i)
coroutine.yield()
end
end)
coroutine.resume(co) --> co 1
coroutine.resume(co) --> co 2
coroutine.resume(co) --> co 3
coroutine.resume(co) --> co 4
coroutine.resume(co) --> co 5
coroutine.resume(co) --> 什么都不打印
当协同A唤醒协同B后, 协同A此时状态为'正常'态, B为'运行'态
- 传递参数
co = coroutine.create(function (a,b,c)
print("co", a, b, c)
end)
coroutine.resume(co, 1, 2, 3) --> co 1 2 3
- 生产者-消费者
function receive()
local status,value = coroutine.resume(producer)
return value
end
function send(x)
coroutine.yield(x)
end
producer = coroutine.create(function ()
while true do
local x = io.read()
send(x)
end
end)
consumer = coroutine.create(function ()
while true do
local x = receive()
io.write(x, "\n")
end
end)
coroutine.resume(consumer)
七. 内部实现
7.1 Lua中的值(TValue)
- tt : 用于标识类型
- p : 存储的light userdata
- gc : 需要回收的值
7.2 字符串(TString)
- 字符串, 一旦创建, 就无法修改, 不使用时会被垃圾回收(GC)
- 分为长字符串和短字符串, 界线由宏LUAI_MAXSHORTLEN决定,默认为40
- 所有短字符串, 均被放在global_State.strt中, strt是stringtable, 是一个哈希表
- 相同的短字符串, 在同一个lua_State中, 只会存在一份
- 长字符串则独立存放(TODO), 没有做唯一化
7.3 表(Table)
- lua中唯一的数据结构
- 由 数组部分 + 哈希部分 实现
7.3 闭包
一个闭包, 是由一个函数指针, 加一个upvalue组成 upvalue中记录了所有外层函数变量
- 当外层函数没有返回时, 闭包的upvalue是直接指向数据栈上变量的位置. 所以这时候调用闭包函数访问外层变量, 其实就是直接访问外层的变量
- 当外层函数返回时, 外层变量在出栈的时候, 若被upvalue引用, 则会将变量从数据栈复制到upvalue中