1、loadstring、dofile和loadfile的用法和区别:
(1)对loadstring,程序示例如下:
f = loadstring("i = i + 1")
i = 0
f() print(i)
f() print(i)
很明显,loadstring将一个语句块加载为一个函数,并返回这个函数。loadstring使用方便灵活,但是它的开销也比较大。
(2)dofile是用于加载并执行外部文件
dofile("F:\\LuaProject\\day01.lua")--加载并运行外部文件
要注意dofile里面要使用绝对路径。
(3)loadfile用于加载外部文件但不马上执行,等待调用。这是它与dofile的区别之处。
file = loadfile("F:\\LuaProject\\day01.lua") --加载外部文件,但并不马上执行
local func = assert(file) --返回一个函数以供调用
func() --需要时就能调用
2、闭包:简单来说,闭包就是函数中的函数,外层为父函数,内层就是闭包。它最大的优点有两个,一是可以读取父函数的变量,二是将这些变量的值始终保存在内存中。示例代码如下:
function func(a)
local a = a or 0
local fun = function() --被嵌套的函数称为闭包
a = a + 1
print(a)
end
return fun
end
local func1 = func(3)
local func2 = func(10) --后面的参数不影响前面的参数,这是闭包的优点
for i = 1, 10 do
func1()
func2()
end
闭包与其他函数最大的区别是,两次调用函数,使用不同的参数时,前后互不影响。这样就可以实现只改变参数而使程序做出不同的行为。
3、协程:协程与线程差不多,也就是一条执行序列,拥有自己独立的栈、局部变量和指令指针,同时又与其他协程共享全局变量和其他大部分东西。协程与线程的区别在于,一个具有多个线程的程序可以同时运行几个线程,二协程却需要彼此写作地运行。就是说,一个具有多个协程的程序在任意时刻只能运行一个协程,并且正在运行的协程只会在其显示地要求挂起时,它的执行才会暂停。
协程创建:coroutine.create(),协程挂起:coroutine.yield()
协程状态:coroutine.status(),协程运行:coroutine.resume()
示例代码如下:
function coroutineFunc()
local co = coroutine.create( --创建一个协程,里面封装了一个匿名函数
function(a , b)
for i = 1, 2 do
print(i.." "..a+b)
coroutine.yield() --协程挂起,每次循环都执行这个操作
end
end)
return co --返回这个协程
end
local co = coroutineFunc()
print(coroutine.status(co)) --打印协程的状态
coroutine.resume(co,3,6) --调用协程,需要传递给内部匿名函数两个参数
coroutine.resume(co,5,6) --调用多少次写多少遍,只有第一次传入的值是有效的
coroutine.resume(co,5,6)
--[[因为内部函数循环两次,这里是第三次调用,调用无任何输出,
但是调用完成后协程的状态变成dead]]
print(coroutine.status(co)) --打印协程的状态:dead
4、Lua中的链表。每个结点以一个table来表示,一个“链接”只是节点table中的一个字段,该字段包含了对其他table的引用。
--测试链表
list = {next = list, value = 1}
list = {next = list, value = 2}
list = {next = list, value = 3}
list = {next = list, value = 4}
list = {next = list, value = 5}
local l = list
while l do
print(l.value)
l = l.next
end
5、Lua 中的每个值都可以用一个 metatable。 这个 metatable 就是一个原始的 Lua table , 它用来定义原始值在特定操作下的行为。Lua在创建新table时不会创建元表。
metatable 中的键名为 事件 (event) ,把其中的值叫作 元方法 (metamethod)。可以通过 getmetatable
函数来查询到任何一个值的 metatable。可以通过 setmetatable
函数来替换掉 table 的 metatable 。但不能从 Lua 中改变其它任何类型的值的 metatable (使用 debug 库例外); 要这样做的话必须使用 C API 。
示例代码如下:
--[[下面这个 getbinhandler 函数定义了 Lua 怎样选择一个处理器来作二元操作。
首先,Lua 尝试第一个操作数。 如果这个东西的类型没有定义这个操作的处理器,
然后 Lua 会尝试第二个操作数。 ]]
function getbinhandler (op1, op2, event)
return metatable(op1)[event] or metatable(op2)[event]
end
--op1 + op2 的行为
function add_event (op1, op2)
local o1, o2 = tonumber(op1), tonumber(op2)
if o1 and o2 then -- 两个操作数都是数字?
return o1 + o2 -- 这里的 '+' 是原生的 'add'
else -- 至少一个操作数不是数字时
local h = getbinhandler(op1, op2, "__add")
if h then
-- 以两个操作数来调用处理器
return h(op1, op2)
else -- 没有处理器:缺省行为
error(···)
end
end
end
print(add_event(1,2)) --输出结果是3
6、Lua提供了一种可以改变table行为的方法。有两种方法可以改变table的行为:查询table及修改table中不存在的字段。实际上,当访问一个table中不存在的字段时,这些访问会促使解释器去查找一个叫做__index 的元方法,如果没有这个元方法,那么访问结果才为nil。验证代码如下:
--创建一个名字空间
Window = {}
--使用默认值创建一个原型
Window.prototype = {x = 0, y = 0, width = 100, height = 100}
Window.mt = {}--创建元表
--声明构造函数
function Window.new(o)
setmetatable(o,Window.mt)
return o
end
--定义__index元方法
Window.mt.__index = function(table, key)
return Window.prototype[key]
end
--创建一个窗口,并查询一个它没有的字段
w = Window.new{ x = 10, y = 20}
print(w.width)--最后结果是100,证明w调用了它的元方法__index
7、单一方法:当对象只有一个方法时,可以不用创建接口table,但要将这个单独的方法作为对象表示来返回
function newObject(value)
return function(action, v)
if action == "get" then
return value
elseif action == "set" then
value = v
else error("error..............")
end
end
end
d = newObject(0)
print(d("get"))
d("set",10)
print(d("get"))
8、Lua数学库:三角函数:sin、cos、tan、asin、acos等
指数和对数函数:exp、log、log10
取整函数:floor、ceil
最大最小:max、min
随机数:random、randomseed
变量:pi、huge(Lua中可以表示的最大的数字)
所有的三角函数都使用弧度单位,可以用函数deg和rad来转换角度和弧度。