起因
因为项目原因,开始学习lua。
想法
刚开始我是拒绝的。要我写lua?那不是脚本语言吗?不是c#,不是面向对象语言,那我费了老多时间学的设计模式还有积累的经验不是没得用了?
然而,经过几天的学习之后,我只想说一句:“真香”。
lua是一个很灵活,很优雅的语言。
1、它是弱类型的,即变量不用声明类型,还可以赋值为任意类型(用过“大家都会”的python的人应该知道)。【灵活度+1】
2、运用了函数式编程的思想,将function(函数)作为first class(“一等公民”),属于基本数据类型,可以赋值给变量。【灵活度+2】
3、提供了“万能”的数据类型table,用起来就是key-value的哈希表。再加上1,2两条,模拟面向对象中的“类”轻而易举。【灵活度+3】
4、提供了神奇的metatable(元表)和它的_index(元方法)。可以用于实现面向对象的继承,多态,保存“类”的信息。【灵活度+1024】
工作
1、数据类型(8种)
-- 短注释
--[=[ 长注释:"="用于匹配开始与结束的位置 ]=]
print(type(nil)) --> nil
print(type(true)) --> boolean
print(type(3.14*2)) --> number
print(type("Hello world")) --> string
print(type(type(X))) --> string
print(type(print)) --> function
print(type(type)) --> function
-- 科学记数法
print(type(2e1))
-- "[[]]"可表示字符串,注意里面会包含换行符
html = [[
<a>test</a>
]]
print(html)
-- string与number计算时,string会被转化为number
print("1"+1)
--print('a'+1)
-- ".."用于连接字符串
print("a".."b")
--#用于获得字符串的长度
s = "ab"
print(#s)
结果:
nil boolean number string string function function number <a>test</a> 2 ab 2
PS:
nil:未赋值变量的默认值,表示无效值。在条件表示式中相当于false。赋给全局变量后,GC会回收。
boolean:false/true
number:双精度实浮点数(不像其他语言有多类型数字)。支持科学记数法:e表示10的几次方。
string:用 双引号/单引号/[[内容]] 来表示。..可连接两个字符串。#取长度。以nil结尾。
userdata:表示任意存储在变量中的C数据结构。(暂时没研究)
thread:用于协程。(暂时没研究)
以下重点讲function和table
function
以end为结尾。支持多返回值,可变参数。
function factorial(n)
if n == 0 then
return 1
else
return n * factorial(n - 1)
end
end
print(factorial(3))
--将factorial函数赋值给f变量
f = factorial
print(f(3))
function maximum (a)
local mi = 1 -- 最大值索引
local m = a[mi] -- 最大值
for i,val in ipairs(a) do
if val > m then
mi = i
m = val
end
end
return m, mi
end
print(maximum({8,10,23,12,5}))
function average(...)
result = 0
local arg={...} --> 局部变量arg 为一个表,,将传入的参数赋给它
for i,v in ipairs(arg) do
result = result + v
end
--[[ select函数中的第一个参数为selector,第二个参数为传入处理的变参。如果selector的值为数字n,那么select函数返回变参中的第n个参数,如果selector的值为'#',select函数会返回可变参数的数量。(等价于#arg)]]
print("input " .. select("#",...).. " numbers")
return result/#arg
end
print("average is ",average(1,2,3))
结果
6 6 23 3 input 3 numbers average is 2
table
table 使用关联型数组,可用任意类型的值作为数组的key(索引),但这个值不能是 nil。不固定大小。
table可用于表示其他语言中的类,模块。
-- 初始化table,不初始化的变量不能当table用,会报错
t = {}
-- 指定值
t[1]= "a"
t["key"]= "val"
print(t[1],t["key"])
-- 调用require加载模块后,获得以模块名为名的table,即可使用
require("<模块名>")
闭包:函数内嵌套函数。
这里的函数f2可以访问参数n,而n是外部函数f1的局部变量。在f2中,变量n即不是全局变量也不是局部变量,将其称为一个非局部变量(non-local variable)或upvalue。upvalue实际指的是变量而不是值,这些变量可以在内部函数之间共享,即upvalue提供一种闭包之间共享数据的方法。
function f1(n)
--函数参数n也是局部变量
local function f2()
print(n) --引用外部函数的局部变量
end
return f2
end
g1 = f1(2015)
g1() -- 打印出2015
g2 = f1(2016)
g2() -- 打印出2016
具体请参考:https://blog.csdn.net/MaximusZhou/article/details/44280109
2、语法
while(condition) do
statements
end
repeat
statements
until( condition )
for init,max/min value, increment
do
for init,max/min value, increment
do
statements
end
statements
end
-- var以exp3为步长(不指定的话默认为1),从exp1变化到exp2。若exp为表达式或函数,则仅会在开始前一次性求值。
for var=exp1,exp2,exp3 do
<执行体>
end
-- 泛型 for 循环。通过一个迭代器函数来遍历所有值,即其他语言中的foreach 语句。这里ipairs是Lua提供的一个迭代器函数,用来迭代数组。
a = {"one", "two", "three"}
for i, v in ipairs(a) do
print(i, v)
end
3、metatable(元表)和元方法
通过setmetatable(table,metatable):对指定 table 设置元表,如果元表(metatable)中存在 __metatable 键值(保护元表,不可读写),setmetatable 会失败。
getmetatable(table):返回对象的元表(metatable)。
元方法:metatable的默认键值。定义了table的原始的某些特定行为(例如加减乘除,大小等于(c++的重载运算符的既视感),基类)。用“ _ ”开头。
_index元方法
最常用的键值,用于实现继承其他table。当访问table的没有值的key时,lua会去查找该table的metatable中的 _index(也是一个table)对应key的值,再没有就继续递归查找 _index的 metatable中的 _index,直到最后nil。
mt = {a = 1}
t = setmetatable({},{_index = mt})
print(t.a)
参考: