- 1, 有状态迭代器 使用了闭包技术
- 无状态迭代器 利用for循环保存状态
- 多状态迭代器 利用tab保存了多个状态
- 真正的迭代器 迭代器中遍历所有的元素,用传入的函数以迭代元素作为操作对象处理
- 2, 函数与闭包
- 函数的形式,当函数只有1个参数的时候,如果这个参数是字符串或者是{}的tab构造的时候,()调用符可以省略
- 多返回值:总是调整函数返回值的个数适应环境
- x, y = foo2(), 20 --x=a, y = 20
- x,y = foo0(), 20, 30 --x=nil, y = 20
- print(foo2(), 1) --a 1
- print(foo2()) --a b
- b = {foo0(), foo2(), 4} -- b[1]=nil, b[2]=a, b[3]=4
- 使用()强制函数返回值为一个
- print((foo2()))
- 3, unpack
- function unpack(t, i)
- ii = i or 1
- if t[i] then
- return t[i],unpack(t,i+1)
- end
- end
- function g(a, b, ...) end
- call params
- g(3) a=3, b=nil, arg={n=0}
- g(3,4) a=3, b=4, arg={n=0}
- g(3,4,5,8) a=3, b=4, arg={5, 8; n=2}
- 4, 选择参数
- local _,x = string.find(s, p)
- -- now use x
- function select(n, ...)
- return arg[n]
- end
- 5, 命名参数
- rename{old="temp.lua", new="tempX.lua"}
- function rename(arg)
- return os.rename(arg.old, arg.new)
- end
- 6, 闭包
- 例1:
- function newCounter()
- local i = 0
- return function()
- ii = i + 1
- return i
- end
- end
- 例2:
- function newCount()
- local i = 0
- function kcount()
- ii = i + 1
- return i
- end
- return kcount
- end
- 例3:
- do
- local oldsin = math.sin
- local k = math.pi/180
- math.sin = function (x)
- return oldsin(x*k)
- end
- end
- 例4:
- do
- local oldsin = math.sin
- local k = math.pi/180
- function math.sin(x)
- return oldsin(x*k)
- end
- end
- 7, 递归调用
- 形式1:
- local fact
- fact = function(n)
- if n == 0 then
- return 1
- else
- return n*fact(n-1)
- end
- end
- 形式2:
- local f, g
- function g()
- f()
- end
- function f()
- g()
- end
- 8, 尾调用
- function f(x)
- return g(x)
- end
- 由于g不需要f函数了,所以可以不再为f保留栈空间了
- 支持不保存栈空间的方式,称为支持正确的尾调用
- 下面写法是要保留栈的:
- function f() g(x) return end --f要负责丢弃g的返回值
- return g(x) + 1 --f要负责等g的返回值,并与1相加
- return x or g(x) --f负责计算表达式的返回值
- return (g(x)) --f负责计算表达式的返回值
- 下面的写法是不保留栈的:
- return x[i].foo(x[j] + a*b, i + j) --在调用之前会先计算表达式
- 9,lua中把chunk当做函数处理, 在chunk内可以声明局部变量的
- 例子:
- function f()
- function foo()
- print("test...")
- end
- end
- --直接执行foo()则显示错误, 因为还没有被定义, 如果要定义则必须运行函数f
- --先执行f()然后再执行foo()则显示test...
- foo.lua
- function foo()
- print("test...")
- end
- f = loadfile("foo.lua")后, foo被编译了,但还没有定义,如果要定义则必须运行chunk
- 10, loadstring 从字符串中读入chunk
- loadfile 从文件中读入chunk
- 两个函数的返回值,当chunk中发生错误是,返回nil, 错误码
- 两个函数总是在全局环境中编译它的串
- 11, error抛出异常, error抛出的异常不止可以是字符串,也可以是tab
- pcall捕获异常, 如果函数正常,则返回值, true, 返回列表....
- 函数捕获到了异常,则返回nil, 错误信息
- 例:
- function foo()
- error({code=1, info="故意抛出的异常"})
- end
- local state, err = pcall(foo)
- if not state then
- print(err.code, err.info)
- end
- 12, assert(f(), errmsg) 检查f函数的第一个返回值,如果为nil,则抛出错误信息errmsg, 否则就返回f()的第一个参数
- assert(f()) 检查f函数的第一个返回值,如果为nil,则抛出错误信息为f()的第2个返回值
- 13, 表明错误发生地儿
- function foo (str)
- if type(str) ~= "string" then
- error("string expected")
- end
- end
- foo({x=1}), 由于调用方式的错误,导致错误的发生,但是错误会定位在foo函数里面
- 这种情况有时候让人分不清是调用问题,还是被调用函数的问题,为了表明问题发生的
- 实际情况,可以用运行级别来表示;
- 运行级别1,为你自己的运行级别
- 运行级别2,则为你的被调用函数的运行级别
- function foo (str)
- if type(str) ~= "string" then
- error("string expected", 2)
- end
- end
- 14, print(package.loadlib()) 来判断是否能加载或者打开动态链接库
- 15, require
- require的两点功能
- 1, require会搜索目录加载文件
- 2, require会判断是否文件已经加载了
- package.path里面的路径
- ?;?.lua;c:\wiindow\?;/usr/local/lua/?/?.lua
- 例如:
- require "world"
- package.loaded["world"]的值为true
- 16, 协作与线程
- co = coroutine.create(function (param1, param2)
- for i= 0, 8 do
- print(i)
- end
- coroutine.yield(param1, param2)
- print("ok")
- return param1+2, param2+2
- end)
- a, b, c = coroutine.resume(co, 1, 2) --等待代码执行完或者遇到yield
- print("1:", a, b, c)
- a, b, c = coroutine.resume(co)
- print("2:", a, b, c)