Lua学习笔记-Day03

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来转换角度和弧度。

你可能感兴趣的:(Lua学习笔记-Day03)