Lua基础

本文介绍了Lua的基础知识,包括类型系统中的string、number、function、boolean、nil、userdata和thread,重点讲解了table的遍历。在表达式部分,讨论了算术操作符、关系操作符、逻辑操作符、字符串连接以及优先级。还提到了table的构造方式,如通过初始化创建和赋值。

git地址
图片版地址
Lua
1、类型
string number function boolean nil userdata(自定义) thread table
1.1 table
1.1.1 遍历
for i = 1, #a do
print(a[i])
end
2、表达式
2.1 算术操作符
+ - * / % ^
x^0.5 = x的平方根. x^(-1/3) = x立方根的倒数
2.2 关系操作符
2.2.1 < > <= >= == ~=(不等)
2.2.2 对于table、userdata、和函数 ,Lua 是做引用比较的,只有当他们引用同一个对象时,才认为他们是相等的
a = {}; a.x = 1; a.y = 1;
b = {}; b.x = 1; b.y = 1;
c = a;
结果 : a == c; a ~= b;
2.2.3 只能对两个数组或者字符串作大小性比较。Lua是安装字母次序比较字符串的,具体的字母次序取决于对Lua的区域设置
“qwertyuiop” 中 “qwe” > “qwr”
2.3 逻辑操作符
and、or、not 所有的逻辑操作符将false 和 nil 视为假,将其他的任何东西视为真
2.3.1 and print(4 and 5) –>5
print(false and 4) –>false
or print(4 or 5) –>5
print(false or 5) –>5
not 永远只返回true 或 false
print(not nil) –>true
print(not false) –>true
2.4 字符串连接 ..
print(“Hello” .. “World”) –>HelloWorld
print(0 .. 1) –>01
#Lua 中的字符串是不可变的值,连接操作符只会创建一个新的字符串,而不会对其原操作数进行任何改变
a = “Hello”
print(a .. “World”) –>HelloWorld
print(a) –>Hello
2.5 优先级
^ not # -(负号) * / % + - .. < > <= >= ~= == and or
^ .. 为右结合
a + i < b / 2 + 1 ======= (a + i) < ((b / 2) + 1)
x^y^z ====== x^(y^z)
2.6 table 构造式
用于创建和初始化table的表达式。Lua特有的一种表达式。
days = {“1”, “2”, “3”}
a = {x = 10, y = 20}
a = {}; a.x = 10; a.y = 20;

            p = {color = "blue", thick = 2, npoints = 4,
                {x = 1, y = 0},
                {x = 2, y = 3},
                {x = 4, y = 5},
                {x = 6, y = 7}
                }
            print(p[2].x)
            print(p[1].y)
            print(p.color)   
    2.7 链表
        list = nil
        for line in io.lines() do
            list = {next = list, value = line}
        end
3、语句
    3.1 赋值
        a, b = 1, 2
        x, y = y, x 值互换
    3.2 局部变量
        local i = 1
        local x = x //声明一个局部变量并且用一个全局遍历赋值
    3.3 程序块
        do
            local x = 1
        end
    3.4 控制结构
        3.4.1 if then else
            if a < 0 then
                a = 0
            end

            if a < b then
                return a
            else
                return b
            end
        3.4.2 while
            local i = 1
            while a[i] do
                print(a[i])
                i = i + 1
            end
        3.4.3
            repeat
                line = io.read()
            until line ~= ""
            print(line)
        3.4.4 for
            数字型for
                for i=1,10,1 do
                    print(i)
                end 
            泛型for
                days = {"Sun", "Mon", "Tue", "Wed", "Thurs", "Fri", "Sat"}
                revDays = {}
                for k, v in pairs(days) do
                    revDays[v] = k
                end
                for v in pairs(revDays) do
                    print(v)
                end
        3.4.5 break \ return
            由于语法构造的原因,break 和 return 只能是一个快的最后一条语句,
            他们应是程序块的最后一条语句,或者是 end、else、until 前的一条语句
            3.4.5.1 break
                local x = 1
                while x do
                    if x == 10 then break end
                    x = x + 1
                    print(x)
                end
            3.4.5.2 return
                function  foo()
                    return  -------->使用错误
                    do return end  -------->使用正确
                    x = 1
                    y = x
                end
4、函数
    函数需要将所有参数放到一对圆括号中,即使调用函数时没有参数,也必须写出一对括号。
    特例:一个函数若只有一个参数,并且此函数是一个字面字符串或 table 构造式那么圆括号可有可无
        print "hello"       ===         print("hello")
        dofile 'a.lua'      ===         dofile('a.lua')
        print [[a multi-linemessage]]       ===         print([[a multi-linemessage]])
        f{x = 10, y = 20}       ===         f({x = 10, y = 20})
        type{}          ===         type({})
    4.1 多重返回值
        function customMax(t)
            local  mi = 1
            local  max = t[mi]
            for i, val in pairs(t) do
                if val > max then
                    max = val
                    mi = i
                end
            end
                return mi, max
        end
        x, y = customMax {10,4,1,5,12,53,123,54,2,33,44,64}
        print(x, y)
    4.2 变长参数
        function customAnd( ... )
            local x = 1
            for i, val in pairs(...) do
                x = x + val
            end
            print(x)
        end
        customAnd({10,2,3,1})
    4.3 具名实参
        rename(old = "temp.lua", new = "temp1.lua")  ------>无效
        rename( {old = "temp.lua", new = "temp1.lua"} ) ------->有效,括号可以省略
5、深入函数
    function foo(x) return 2 * x end
    foo = function(x) return 2 * x end
    5.1 高阶函数
        接受另一个函数作为实参的称其为"高阶函数"
        names = {"Peter", "Paul", "Mary"}
        grades = {Mary = 10, Paul = 7, Peter = 8}
        table.sort(names, function ( n1, n2 )
            return grades[n1] > grades[n2]
        end)
    5.2 closure (闭合函数)
        function newCounter( )
            local  i = 0
            return function ( )
                i = i + 1
                return i
            end
        end

        c1 = newCounter()
        print(c1()) -------------->1
        print(c2()) -------------->2
    5.3 尾调用(proper tail call)
        function f(x) return g(x) end
        当f调用完之后就再无其他事情可做了。
        因此在这种情况中程序就不需要返回那个"尾调用"所在的函数了.所以在"尾调用"之后,
        程序也不需要保存热河关于该函数的栈信息了。
        当g返回时,执行控制权可以直接返回到调用f的那个点上。使得在进行"尾调用"时不耗费任何栈控件。
        称为"尾调用消除"
        return x[i].foo(x[j] + a * b, i + j)  ---是
        return g(x) + 1 ---不是
6、迭代器与泛型for
    6.1 迭代器
        function allwords( )
            local line = io.read()  --当前行
            local pos = 1           --一行中的当前位置
            return function ( )     ---迭代器函数
                while line do       ---若为有效的行内容就进入循环
                    local s, e = string.find(line, "%w+", pos)
                    if s then       ---是否找到一个单词
                        pos = e + 1         ---该单词的下一个位置
                        return string.sub(line, s, e)       ---返回该单词
                    else
                        line = io.read()        ---没有找到单词,尝试下一行
                        pos = 1                 ---在第一个位置上重新开始
                    end
                end
                return nil              ---没有其余行了,遍历结束
            end
        end
    6.2 泛型for
        for <var-list> in <exp-list> do
            <body>
        end
        <var-list> 是一个或多个变量名的列表,以逗号分隔
        <exp-list> 是一个或多个表达式的列表,以逗号分隔
        for k, v in pairs(t) do print(k, v) end
7 编译 loadstring
    i = 0
    f = loadstring("i = i + 1; print(i)")
    7.1  loadstring 在编译时不涉及词法域,所以操作的是全局变量,因为loadstring总是在全局环境中编译它的字符串
        i = 32
        local i = 0
        f = loadstring("i = i + 1; print(i)")
        g = function ( )
            i = i + 1
            print(i)
        end

        f() ------>33
        g() --------1
    7.2 如果代码中有语法错误,loadstring会返回nil,最终的错误消息可能会是"attempt to call a nil value"
    为了更清楚的显示错误消息,使用assert
        assert(loadstring(s))()
    7.3 速度
        f = loadstring("i = i + 1")
        f = function (  )
            i = i + 1
        end
        第二块代码快的多,因为他只在编译对应用程序块时编译一次
        第一块代码在每次调用loadstring 时都被重新编译
8、error检测
    8.1 数字检测 tonumber(i) 如果为数字则返回数字否则返回nil
    8.2 assert()
        函数检查其第一个参数是否为true,若为true,则简单的返回该函数,否则引发一个错误,输出第二个参数
    8.3 pcall ------protected call
        保护模式调用
9、协程
    9.1 四种状态
        suspended 挂起、running 运行、dead 死亡、normal 正常
        当创建一个协同程序时,它处于挂起状态。
    9.2 yield
        co = coroutine.create(function ( )
            for i=1,10 do
                print(i)
                coroutine.yield()
            end
        end)
        该函数可以让一个运行中的协同程序挂起,而之后可以再恢复他的运行.
    9.3 resume 是在保护模式中运行的。因此,如果在一个协同程序的执行中发生任何错误,lua是不会显示错误信息的。
    而是将执行权返回给resume调用。
        当一个协同程序A唤醒另一个协同程序B时,协同程序A就处于一个特殊状态,既不是挂起状态,也不是运行状态,称为"正常"状态
        返回值为是否有错误 和 yield的返回值
        co = coroutine.create(function ( )
            yield return 0, 1, 3
        end)
        print(coroutine.resume(co)) ------>true 0 1 3
    9.4 生产者-消费者
        function producer(  )
            while true do
                local x = io.read()
                send(x)
            end
        end

        function consumer( )
            while true do
                local x = reveive()
                io.write(x, "\n")
            end
        end

        function receive( )
            local status, value = coroutine.resume(producer)
            return value
        end

        function send( x )
            coroutine.yield(x)
        end
    9.5 过滤器(filter)
        function reveive( prod )
            local status, value = coroutine.resume(prod)
            return value
        end

        function send( x )
            coroutine.yield(x)
        end

        function producer(  )
            return coroutine.create(function ( )
                while true do
                    local x = io.read()
                    send(x)
                end
            end)
        end

        function filter( prod )
            return coroutine.create(function ( )
                for line = 1, math.huge do
                    local x = receive(prod)
                    x = string.format("%5d %s", line, x)
                    send(x)
                end
            end)
        end

        function consumer( prod )
            while true do
                local x = reveive(prod)
                io.write(x, "\n")
            end
        end
10、数据结构
    10.1 字符串缓冲
        逐行地读取一个文件
            local buff = ""
            for line in io.lines() do
                buff = buff .. line .. "\n"
            end
11、元表 metatable 元方法 meatmethod
    Lua 中只能设置table的元表
    可以通过元表来修改一个值的行为,使其在面对一个非预定义的操作时执行一个指定的操作。
    action = {} --元表

    function action.new( value )
        local temp = {}
        setmetatable(temp, action)  --元表赋值
        for k, v in pairs(value) do
            temp[#temp + 1] = v
        end
        return temp
    end

    -- table转string
    function action.tostroing( value )
        return table.concat( value, ", ", 1, #value )
    end

    function action.add( source,  addition)
        -- local temp = {}
        -- setmetatable(temp, action)
        -- local  source = value.source
        -- local  addition = value.addition
        for k, v in pairs(addition) do
            source[#source + 1] = v
        end
        return action.tostroing(source)
    end

    a = action.new{1,2,3}
    b = {4,5,6}

    -- print(action.add{source = a, addition = b})
    print(action.add(a, b))

    11.1 在元表中,每种算术操作符都有对应的字段名。
    __add __mul __sub __div __unm(相反数) __mod(取模) __pow(乘幂) __concat(描述连接操作符的行为)

    11.2 重载操作符 __index原方法 __newindex
    action = {}

    function action.tostroing( value )
        return table.concat( value, ", ", 1, #value )
    end

    function action.__add( a, b )
        for v in pairs(a) do
            a[v] = a[v] + b
        end
        return action.tostroing(a)
    end

    function action.__index(table, key)
        print("当访问table中不存在的key值时会调用 __index 方法,比如现在 : " .. key)
        return "error"
    end

    function action.__newindex(table, key, value)
        local temp = table
        print("现在将要添加新的key值和与其对应的value :")
        print("key : " .. key)
        print("value : " .. value)
        -- temp[key] = value
        -- return action.tostroing(table)
    end

    a = {1,2,3}
    setmetatable(a, action)

    print("重载 + :")
    print( a + 3)
    print("\n")

    b = {1,2,3}
    setmetatable(b, action)

    print("访问table中不存在的key值 : ")
    print(b[4])
    print("\n")

    c = {1,2,3}
    setmetatable(c, action)

    print("添加新的key值和与其对应的value : ")
    c[4] = 4
    print(action.tostroing(c))
    print("\n")

    11.3 __index 还可以是一个table
        当它是一个函数时候,lua以table和不存在的key作为参数来调用该函数,当它是一个table时候,
        lua就以相同的方式来重新访问这个table
        a = {1,2,3}
        b = {4,5,6,7}
        c = {}

        setmetatable(a, c)

        c.__index = b

        print(a[4]) -------->7

12、环境
    Lua 将所有的全局变量保存在一个常规的table _G 中
        for n in pairs(_G) do
            print(n)
        end
    12.1 具有动态名字的全局变量
        有些变量的名称存储在另一个变量中,或者需要计算才能得到,为了获取这个变量的值
            value = loadstring("return" .. varname)()
            如果varname 是 x ,那么连接操作就是字符串return x。
            这样做包含了一个新程序块的创建和编译。
            value = _G[varname] 效率高
    12.2 全局变量声明
        大型程序中简单的检测与创建全局变量
        setmetatable(_G, {
            __index = function ( _, n )
                print("没有此全局变量" .. n)
            end,
            __newindex = function ( table, k, value )
                print("add a global variable")
                rawset(table, k, value)
            end
            })

        a = 1;
        print(a)
        print(b)
    12.3 通过setfenv来改变一个函数的环境
        a = 1
        setfenv(1, {g = _G})
        g.print(a)  ----->nil
        g.print(g.a)    ---->1
13、模块与包
    13.1 require 使用模块
        testLib.lua文件:
            testLib = {}

            function testLib.new( value )
                local temp = {}
                for k, v in pairs(value) do
                    temp[#temp + 1] = v
                end
                return temp
            end

            return testLib
        test.lua文件
            lib = require "testLib"
            a = lib.new{1,2,3}

            function tostroing( value )
                return table.concat( value, ", ", 1, #value )
            end

            print(tostroing(a)) --->1,2,3
    13.2 module 
        testLib.lua 文件
            lib = require "testLib" 
            a = lib.new{1,2,3}

            function tostroing( value )
                return table.concat( value, ", ", 1, #value )
            end

            print(tostroing(a))
        test.lua 文件
            lib = require "testLib" 
            a = lib.new{1,2,3}

            function tostroing( value )
                return table.concat( value, ", ", 1, #value )
            end

            print(tostroing(a))
    13.3 require 目录
        lua 没有目录的概念
        require "a.b"
        ./a/b.lua
        /usr/local/lua/a/b.lua
        /usr/local/lua/a/b/init.lua
14 面向对象
    14.1 self
        使用self参数是所有面向对象语言的一个核心,
        大多数面向对象语言都能对程勋元隐藏部分self参数,
        从而使程序员不必显示地声明这个参数,
        Lua只需使用冒号就能隐藏该参数
            function Account:withdraw( v )
                self.balance = self.balance - v
            end
        调用时:
            a = {balance = 0, withdraw = Account.withdraw}
            a:withdraw(100)
    14.2 继承
        示例1:
            a = {1,2,3}
            b = {4,5,6,7}
            c = {}

            setmetatable(a, c)

            c.__index = b

            print(a[4])----->7
        示例2:
            a = {base = 1}
            setmetatable(a, a)

            function a:add( value )
                self.base = self.base + value
                return self.base
            end

            b = {}
            setmetatable(b, b)
            b.__index = a

            c = {}
            setmetatable(c, c)
            c.__index = a

            print(a:add(1)) --->2
            print(b:add(1)) --->3
            print(c:add(1)) --->3
    14.3 多重继承
        local function search( k, plist )
            for i=1, #plist do
                local v = plist[i][k]
                if v then return v end
            end
        end

        function createClass( parents )
            local c = {}
            local parents = parents
            setmetatable(c, {__index = function ( t, k )
                return search(k, parents)
            end})
            c.__index = c

            function c:new( o )
                o = o or {}
                setmetatable(o, c)
                return o
            end

            return c
        end

        a = {aBase = 1}
        setmetatable(a, a)
        function a:add( value )
            self.aBase = self.aBase + value
        end

        b = {bBase = 9}
        setmetatable(b, b)
        function b:sub( value )
            self.bBase = self.bBase - value
        end

        c = createClass{a, b}
        c:add(1)
        c:sub(1)
        print("c aBase : " .. c.aBase)
        print("c bBase : " .. c.bBase)
    14.4 私密性 私有性
        function new( init )
            local self = {value = init}
            local add = function ( addition )
                self.value = self.value + addition
            end

            local sub = function ( sub )
                self.value = self.value - sub
            end

            local get = function ( )
                return self.value
            end

            return {add = add, sub = sub, get = get}
        end

        count = new(1)
        count.add(1)
        print(count.get())
    14.5 单一方法 的做法
        function new( init )
            local self = {value = init}

            return function ( action, value )
                if action == "add" then self.value = self.value + value
                elseif action == "sub" then self.value = self.value - value
                elseif action == "get" then return self.value
                end
            end
        end

        count = new(1)
        print("initial value is : " .. count("get"))
        count("add", 1)
        print("after add 1 : " .. count("get"))
        count("sub", 1)
        print("after sub 1 : " .. count("get"))
15 弱引用
    lua自动回收,只回收弱引用的的类型、为nil的全局变量。
    全局变量使用完后需要手动置为nil
    table中有key和value,这两者都可以包含任意类型的对象,
    通常收集器不会回收一个可访问table中作为key或value的对象。
    也就是说这些key和value都是强引用,他们会阻止对其所引用对象的回收。
    在一个弱引用table中。key和value都是可以回收的。
    只要key或者value一方为若引用,那么他们所在的整条目都会从table中删除
    15.1 table 弱引用
        table的弱引用类型是通过其元表中的__mode字段来决定的。
        这个字段的值应为一个字符串,
        如果这个字符串包含'k',那么这个table的key是弱引用
        如果包含'v',那么这个table的value是弱引用
        a = {}
        b = {__mode = "k"}
        setmetatable(a, b)
        key = {}
        a[key] = 1
        key = {}
        a[key] = 2
        collectgarbage()
        for k, v in pairs(a) do
            print(v)
        end -------->2

    15.2 备忘录函数
        空间换时间
        local results = {}
        function mem_loadstring( s )
            local res = results[s]
            if nil == res then
                res = assert(loadstring(s))
                results[s] = res
            end
            return res
        end

        转为弱引用:
        local results = {}
        setmetatable(results, {__mode = "v"})
        function mem_loadstring( s )
            local res = results[s]
            if nil == res then
                res = assert(loadstring(s))
                results[s] = res
            end
            return res
        end
16 数学库
    三角 math.sin cos tan asin acos ...
    指数对数 exp log log10
    取整函数 floor ceil max min
    生成伪随机数 random randomseed
        math.random() ---[0,1)
        math.random(6) ---[1,6]
        math.random(m,n) ---[m,n]
        math.randomseed(os.time()) ---os.time 表示从某个时间点开始至今的秒数
    pi
    huge 为Lua可以表示的最大数字
17 table库
    17.1 插入和删除
        action = {}
        function action.tostring( value )
        return table.concat( value, ", ", 1, #value )
        end

        a = {1,2,3}
        table.insert(a, 1, 4)
        print(action.tostring(a)) --4,1,2,3

        b = {1,2,3}
        table.insert(b, 4)
        print(action.tostring(b)) --1,2,3,4

        c = {1,2,3}
        table.remove(c)
        print(action.tostring(c)) --1,2

        d = {1,2,3}
        table.remove(d, 1)
        print(action.tostring(d)) --2,3
    17.2 排序
        action = {}
        function action.tostring( value )
        return table.concat( value, ", ", 1, #value )
        end

        a = {3,6,1,4,5,2}
        table.sort( a, function ( a, b )
            return a < b
        end )

        print(action.tostring(a)) --1, 2, 3, 4, 5, 6

        table.sort(a, function ( a, b )
            return a > b
        end)

        print(action.tostring(a)) --6, 5, 4, 3, 2, 1
18 字符串库
    18.1 基础字符串函数
        string.len(s) 返回字符串s的长度
        string.rep(s, n) s:rep(n) 返回字符串s重复n次的结果
        string.lower(s) 返回一份s的副本,其中所有的大写字母转换成小写
        string.upper(s) 小写转大写
        string.sub(s, i, j) 字符串s中提取第i个到第j个字符
            字符串第一个字符的索引是1,索引-1代表字符串的最后一个字符
            索引-2代表倒数第二个字符
            string.sub(j, -1) == string.sub(j) 第二个参数默认为-1
        string.char string.byte 用于转换字符及内部数值表示
            string.char(97) --a
            string.byte("abc") --97
            string.byte("abc", 2) --98
            string.byte("abc", 1, 2) --97 98
        18.1.1 format
            print(string.format("pi = %.4f", math.pi)) --- pi = 3.1416
            d = 5; m = 11; y = 1990
            print(string.format("%02d/%02d/%04d", d, m, y)) --- 05/11/1990
            tag, title = "h1", "a title"
            print(string.format("<%s>%s</%s>", tag, title, tag)) ---<h1>a title</h1>
    18.2 模式匹配函数
        fin match gsub(全局替换) gmatch(全局匹配) 
        18.2.1 string.find 返回起始索引和结尾索引,如果没有找到返回nil
            s = "hello world"
            i, j = string.find(s, "hello")
            print(i, j) --- 1 5
            string.find 函数还具有一个可选的第三个参数,他是一个索引告诉函数应该从目标字符串的那个位置开始搜索
        18.2.2 string.match 函数
            string.match("hello world", "hello") -- hello

            data = "Today is 17/7/1990"
            string.match(date, "%d+/%d+/%d+") ---17/7/1990
        18.2.3 string.gsub 
            s, k = string.gsub("all lii", "l", "x") --- axx xii   --3
            可选第四个参数,限制替换次数
            k = 3 替换次数
            18.2.3.1
                第三个参数还可以是一个table(包括_G)
                用来替换
                group = {}
                group.a = "Lua"
                group.b = "great"
                print(string.gsub("$a is $b", "$(%w+)", group)) -- Lua is great  2
                还可以是一个方法
                    s ="a%2Bb%3Dc"
                    s = string.gsub(s, "%%(%x%x)", function ( h )
                        return string.char(tonumber(h, 16))
                    end)
                    print(s) -- a+b=c
        18.2.4 string.gmatch
            d = "123qwertyuiopasdfghjklqwer"
            a = string.gmatch(d, "qwe")
            for w in a do
                print(w) --qwe
            end 
    18.3 模式
        18.3.1
        %a 字母
        %c 控制字母
        %d 数字
        %l 小写字母
        %p 标点符号
        %s 空白字母
        %u 大写字母
        %w 字母和数字字符
        %x 十六进制数字
        %z 内部表示为0的字符
        18.3.2 需要转义的字符 ().%+-*?[]^$
        18.3.3 .- .*的区别
            test = "int x; /*x*/ int y; /*y*/"
            print(string.gsub(test, "/%*.*%*/", "<COMMENT>")) -- int x; <COMMENT>   1
            print(string.gsub(test, "/%*.-%*/", "<COMMENT>")) -- int x; <COMMENT> int y; <COMMENT>  2
        18.3.4 ?
            a = "qwer+1234asdf-5432"
            print(string.gsub(a, "[+-]?%d+", "A")) -- qwerAasdfA    2
        18.3.5 如果模式以'^'起始,那么他只会匹配目标字符串的开头部分
            以'$'结尾,只匹配结尾部分
            a = "123qwer+1234asdf-5432"
            print(string.match(a, "^%d+")) -- 123
            print(string.match(a, "%d+$")) -- 5432
        18.3.6 "%b<x><y>"
            以x开头y结尾的字符串
            a = "hello (13qwer+134asdf-5432)world"
            print(string.gsub(a, "%b()", "")) -- hello world    1 
        18.3.7 捕获
            模式中表示两个字母序列的部分放在一对括号中,就能捕获到
            d = "Today is 17/7/1990"
            d, m, y = string.match(d, "(%d+)/(%d+)/(%d+)")
            print(d, m, y) -- 17    7   1990
        18.3.8 URL 编码
            s ="a%2Bb%3Dc" -- a%2Bb%3Dc
            s = string.gsub(s, "%%(%x%x)", function ( h )
                return string.char(tonumber(h, 16))
            end)
            print(s) --a+b

            a = "%2B"
            print(string.gsub(a, "%%(%x%x)", "A")) -- A 1

            a = "%2B"
            print(string.gsub(a, "%%(%x)", "A")) -- AB  1
        18.3.9 空白捕捉 ()
            print(string.match("hello", "h()")) -- 2
            print(string.match("hello", "l()")) -- 4
    19 I/O模型
        19.1 简单I/O模型
            io.input(filename)调用会以只读模式打开指定的文件,并将其设为当前输出文件。
            之后除非再次调用 io.input ,否则所有的输入都将来源于这个文件。
            io.write(a..b..c)应该尽量避免,io.write(a,b,c)效果相同并且可以避免连接操作。
            19.1.1 write与print不同
                write在输出时不会添加像制表符或回车这样的额外字符
                    print("hello","Lua");
                    print("Hi")
                        --hello Lua
                        --Hi
                    io.write("hello", "Lua");
                    io.write("Hi","\n")
                        --helloLuaHi
                write使用当前输出文件而print总是使用标准输出
                print会自动调用其参数的tostring方法因此他还能显示table、函数和nil
            19.1.2 io.read从当前输入文件中读取字符串,他的参数决定了要读取的数据
                "*all" 读取整个文件
                "*line"读取下一行
                "*number" 读取一个数字
                <num> 读取一个不超过<num>个字符的字符串
            19.1.3 io.lines()迭代器 如果只为了迭代文件中的所有行,那么io.lines迭代器更为合适。
                local lines = {}
                for line in io.lines() do lines[#lines + 1] = line end
                table.sort( lines )
                for _,l in ipairs(lines) do io.write(l, "\n") end
        19.2 完整 I/O 模型
            19.2.1 open
                io.open(要打开的文件名, 模式字符串)
                r 读取
                w 写入 同时会删除文件原来的内容
                a 追加
                b 打开二进制文件
                print(io.open("non-existent-file", "r"))
                    -- nil  non-existent-file: No such file or directory    2
                错误代码的解释依赖于系统
                典型做法
                    local f = assert(io.open(filename, mode))
                    如果打开失败,错误消息会成为assert的第二个参数,然后显示这个信息
            19.2.2 操作
                local f = assert(io.open(filename, "r"))
                local t = f:read("*all")
                f:close()
            19.2.3 性能
                1 一次性读取整个文件比逐行地读取要快一些
                2 如果文件太大无法一次性读取,尽可能大的块读取,例如8KB大小的块
                    为了避免在行中间断开,只需在读取一个块时再加上一行
                        local lines, rest = f:read(BUFFSIZE, "*line")
                        rest 包含了被块所断开的那一行的剩余部分,这样就可以将块与行的剩余部分连接起来,
                        从而得到一个总是起止于行边界上的块
                            local BUFSIZE = 3
                            local f = io.input(arg[1])
                            local cc, lc, wc = 0,0,0 --字符、行、单词计数器
                            while true do
                                local lines, rest = f:read(BUFSIZE, "*line")
                                if not lines then break end
                                if rest then lines = lines .. rest .. "\n" end
                                cc = cc + #lines
                                local _, t = string.gsub(lines, "%S+", " ")
                                wc = wc + t
                                _, t = string.gsub(lines, "\n", "\n")
                                lc = lc + t
                            end
                            print(lc, wc, cc)
            19.2.4 二进制
                local inp = assert(io.open(arg[1], "rb"))
                local out = assert(io.ioen(arg[2], "wb"))
                local data = inp:read("*all")
                data = string.gsub(data, "\r\n", "\n")
                out:write(data)
                assert(out:close())

                调用: lua prog.lua file.dos file.unix
            19.2.5 文件操作
                file:seek() 获取当前位置
                file:seek("end") 获取文件大小
                file:seek("set", current) 恢复位置
    20 操作系统库
        20.1 日期和时间 time 、 date
            print(os.time{year = 2016, month = 1, day = 1, hour = 0, min = 0, sec = 0, isdst = true}) --isdst true 表示夏令时
            print(os.time()) --1451577600
            print(os.date("today is %a", os.time()))    星期简写    today is Mon
            print(os.date("today is %A", os.time()))    星期全写    today is Monday
            print(os.date("today is %b", os.time()))    月份简写    today is Dec
            print(os.date("today is %B", os.time()))    月份全称    today is December
            print(os.date("today is %c", os.time()))    日期和时间   today is Mon Dec  5 13:53:31 2016
            print(os.date("today is %d", os.time()))    一个月中第几天 today is 05
            print(os.date("today is %H", os.time()))    24小时进制小时数   today is 13
            print(os.date("today is %I", os.time()))    12小时进制小时数   today is 01
            print(os.date("today is %j", os.time()))    一年中第几天  today is 340
            print(os.date("today is %M", os.time()))    分钟数 today is 53
            print(os.date("today is %m", os.time()))    月份数 today is 12
            print(os.date("today is %p", os.time()))    上午下午    today is PM
            print(os.date("today is %S", os.time()))    秒数  today is 31
            print(os.date("today is %w", os.time()))    一星期中第几天 today is 1
            print(os.date("today is %x", os.time()))    日期 today is 12/05/16
            print(os.date("today is %X", os.time()))    日期 today is 13:53:31
            print(os.date("today is %y", os.time()))    两位数年份 today is 16
            print(os.date("today is %Y", os.time()))    完整年份    today is 2016
            print(os.date("today is %%", os.time()))

            如果不带任何参数调用date函数,他会使用%c。
            %x %X %c会根据不同的区域和系统而发生变化

            函数 os.clock 会返回当前cpu时间的秒数,一般可用于计算一段代码的执行时间
            local x = os.clock()
            local s = 0
            for i=1,10000 do
                s = s + 1
            end
            print(string.format("elapsed time : %2f\n", os.clock() - x)) --elapsed time : 0.000070
        20.2 其他系统调用
            os.exit() 中止当前程序的执行
            os.getenv() 获取一个环境变量的值
                os.getenv("Home")
                如果一个环境变量没有定义返回nil
            os.execute()运行一条系统命令
                os.execute("mkdir" .. dirname)
    21 C API c调用lua
        #include <stdio.h>
        #include <string.h>
        #include "lua.hpp"
        #include "lauxlib.h"
        #include "lualib.h"

        int main (void){
            printf("go\n");

            lua_State* L = luaL_newstate();

            luaL_openlibs(L);

            lua_close(L);

            return 0;
        }
        21.1 栈操作
            抽象栈在Lua与C之间交换数据
            栈中的每个元素都能保存任何类型的Lua值
            要获取Lua中的一个值时只要调用一个Lua API函数,Lua就会将制定的值压入栈中
            要将一个值传给Lua时,需要先将这个值压入栈,然后调用Lua API,Lua就会获取该值并将其从栈中弹出
            Lua以 先出后进 规范操作栈,当调用Lua时,Lua只会改变栈的顶部
            C有更大的自由度,他可以检索栈中间的元素,插入删除任意位置
            21.1.1 压入元素
                void lua_pushnil(lua_State* L);
                void lua_pushboolean(lua_State* L, int bool);
                void lua_pushnumber(lua_State* L, lua_Number n); --lua_Number是Lua中的数字类型默认为双精度浮点数 或者单精度浮点数或长整数
                void lua_pushinteger(lua_State* L, lua_Integer n); --lua_Integer整数类型足以存储大型字符串的长度
                void lua_pushlstring(lua_State* L, const char* s, size_t* len); --Lua中的字符串不是以零结尾需要长度
                void lua_pushstring(lua_State* L, const char* s);
                还有压入C函数、userdata值的函数

                int lua_checkstack(lua_State* L, int sz) --检查栈中是否有足够空间
            21.1.2 查询元素
                使用索引
                第一个压入元素索引为1 第二个2
                最后压入元素为-1 倒数第二个-2
                21.1.2.1 检查是否为特定类型
                    int lua_is*(lua_State* L, int index);
                    实际上,lua_isnumber不会检测值是否为数字类型,而是检测值是否可以转为数字类型
                    lua_isstring 同样,因此对于任意数字,lua_isstring都返回真
                21.1.2.2 返回栈中原色的类型 lua_type
                    返回一个常量,这些常量定义在头文件lua.h中。
                    LUA_TNIT LUA_TBOOLEAN LUA_TNUMBER LUA_TSTRING LUA_TTABLE LUA_TTHREAD LUA_TUSERDATA LUA_TFUNCTION
                21.1.2.3 取值 lua_to*
                    int lua_toboolean(lua_State* L, int index);
                    lua_Number lua_tonumber(lua_State* L, int index);
                    lua_Integer lua_tointerger(lua_State* L, int index);
                    const char* lua_tolstring(lua_State* L, int index, size_t* len);
                    size_t lua_objlen(lua_State* L, int index);

                    如果指定元素不具有正确的类型,调用这些函数也不会有问题 ,会返回0或者NULL

                    lua_tolstring 函数会返回一个指向内部字符串副本的指针,并将字符串的长度存入最后一个参数len中。
                    Luaua只要保证这个对应的字符串值还在栈中,那么这个指针就是有效的。
                    当Lua调用的一个C函数返回时,LUA就会清空他的栈。
                    所以不要在C函数之外使用在C函数内获得的指向Lua字符串的指针
                21.1.2.4 其他栈操作
                    int lua_gettop(lua_State* L); --栈中元素的个数,栈顶元素的索引
                    void lua_settop(lua_State* L, int index); --将栈顶设置为一个指定的位置,修改栈中元素的数量,高出来的丢弃不足的补nil
                    -- lua_settop(L, 0)能清空栈,也可以用负数来索引
                    一个宏来弹出n个元素 #define lua_pop(L, n) lua_settop(L, -(n) - 1)
                    void lua_pushvalue(lua_State* L, int index); -- 将指定索引上值的副本压入栈
                    void lua_remove(lua_State* L, int index); --删除指定索引上的元素,该位置只上的所有元素下移填补空缺
                    void lua_insert(lua_State* L, int index); --上移该位置之上的所有元素来开辟一个空间,将栈顶元素移到该位置
                        lua_insert(L, -1) -- 将栈顶元素移动到栈顶
                    void lua_replace(lua_State* L, int index); --弹出栈顶的值并将该值设置到指定索引上,但不会移动任何东西

                    #include <stdio.h>
                    #include <string.h>
                    #include "lua.hpp"
                    #include "lauxlib.h"
                    #include "lualib.h"

                    void printStack(lua_State* L){
                        int size = lua_gettop(L);
                        for(int i = 1; i <= size; i++){
                            int t = lua_type(L, i);
                            switch(t){
                                case LUA_TSTRING:{
                                    printf("%s", lua_tostring(L, i));
                                }
                                break;
                                case LUA_TNUMBER:{
                                    printf("%g", lua_tonumber(L, i));
                                }
                                break;
                            }
                            printf("\n");
                        }
                    }

                    int main (void){
                        printf("im in cpp\n");

                        lua_State* L = luaL_newstate();

                        lua_pushnumber(L, 1);
                        lua_pushstring(L, "hello lua");
                        lua_pushnumber(L, 2);

                        printf("source stack is :");
                        printStack(L);

                        // lua_pushvalue(L, 2);
                        // printf("after pushvalue 2, now stack is :\n");
                        // printStack(L);



                        lua_close(L);
                    }

                    编译 gcc /Users/wp/Desktop/Unity基础/cdolua.cpp -llua
    22 扩展应用
        22.1 Lua做配置文件
            test.lua 文件内容
                width = 10
                height = 20
            cdolua.cpp 文件内容 使用c调用lua读取lua写的配置文件
                #include <stdio.h>
                #include <string.h>
                #include "lua.hpp"
                #include "lauxlib.h"
                #include "lualib.h"

                void load(lua_State* L, const char* fname, int* w, int* h){
                    if(luaL_loadfile(L, fname) || lua_pcall(L, 0, 0, 0)){}
                    lua_getglobal(L, "width");
                    lua_getglobal(L, "height");
                    if(!lua_isnumber(L, -2)){}
                    if(!lua_isnumber(L, -1)){}
                    *w = lua_tointeger(L, -2);
                    *h = lua_tointeger(L, -1);
                    printf("width is : %d\n", *w);
                    printf("height is : %d\n", *h);
                }

                int main (void){
                    printf("im in cpp\n");

                    lua_State* L = luaL_newstate();

                    int x = 0;
                    int y = 0;

                    load(L, "test.lua", &x, &y);

                    lua_close(L);
                }

                调试加调用
                    wangpengdeiMac:Unity基础 wp$ gcc /Users/wp/Desktop/Unity基础/cdolua.cpp -llua
                    wangpengdeiMac:Unity基础 wp$ ./a.out 
                    im in cpp
                    width is : 10
                    height is : 20
        22.2 调用方法
            test.lua文件
                function printTest( ... )
                    print(...)
                    return 1
                end
            cdolua.cpp文件
                #include <stdio.h>
                #include <string.h>
                #include "lua.hpp"
                #include "lauxlib.h"
                #include "lualib.h"

                int main (void){
                    printf("im in cpp\n");

                    lua_State* L = luaL_newstate();
                    luaL_openlibs(L);  
                    if(luaL_loadfile(L, "test.lua") || lua_pcall(L, 0, 0, 0)){
                        printf("%s\n", "error loadfile");
                    }

                    lua_getglobal(L, "printTest");
                    lua_pushstring(L, "1234");

                    if(lua_pcall(L, 1, 1, 0) != 0){
                        printf("%s\n", "error lua pcall");
                    }

                    int z = lua_tonumber(L, -1);
                    printf("z : %d\n", z);

                    lua_close(L);
                }
            编译
                wangpengdeiMac:Unity基础 wp$ gcc /Users/wp/Desktop/Unity基础/cdolua.cpp -llua
                wangpengdeiMac:Unity基础 wp$ ./a.out 
                im in cpp
                1234
                z : 1
    23 Luaua 调用 C ----尼玛我这怎么都不能c文件编译成.a或者.so
        23.1 C 函数
            示例:
                static int l_sin(lua_State* L){
                    double d = lua_tonumber(L, 1); //获取参数
                    lua_pushnumber(L, sin(d)); //压入结果
                    return 1; //返回结果的数量
                }
            所有注册到LUA中的函数都具有相同的原型。定义在lua.h 中的lua_CFunction
                typedef int (*lua_CFunction) (lua_State* L);
            在lua使用这个函数之前,必须注册这个函数。可以使用 lua_pushcfunction 来进行注册。
    24 userdata
        userdata 提供了一块原始的内存区域,可以用来存储任何东西.
        lua_newuserdata 会根据指定的大小分配一块内存,并将对应的userdata压入栈中,最后返回这个内存块的地址
        void* lua_newuserdata(lua_State* L, size_t size);
            Demo:
                static struct StudentTag{
                    char* strName;
                    char* strNum;
                    int iSex;
                    int iAge;
                }

                static int Student(lua_State* L){
                    size_t iBytes = sizeof(struct StudentTag);
                    struct StudentTag* pStudent;
                    pStudent = (struct StudentTag*) lua_newuserdata(L, iBytes);
                    return 1;
                }   //新的userdata已经在栈上可以直接返回给lua

                static int GetName(lua_State* L){
                    struct StudentTag* pStudent = (struct StudentTag*)lua_touserdata(L, 1);
                    luaL_argcheck(L, pStudent != NULL, 1, "Wrong");
                    lua_pushstring(L, pStudent->strName);
                    return 1;
                }

                static int SetName(lua_State* L){
                    struct StudentTag* pStudent = (struct StudentTag*)lua_touserdata(L, 1);
                    luaL_argcheck(L, pStudent != NULL, && pName != "", "Wrong");
                    pStudent->strName = pName;
                    return 0;
                }

                lua:
                require "luaDoC"

                local objStudent = Student.new()
                Student.setName(objStudent, "WP")
                Student.setAge(objStudent, 15)

                local strName = Student.getName(objStudent)
                local iAge = Student.getAge(objStudent)

                print(strName)
                print(iAge)
    25  元表
        userdata 可以代表任何类型。所以当用userdata做参数时候并不能保证类型。
        一种辨别不同类型的userdata的方法是,为每种类型创建一个唯一的元表。
        每当创建了一个userdata后,就用相应的元表来标记他。
        每当得到一个userdata就检查他是否拥有正确的元表。
        由于Lua代码不能改变userdata的元表。因此无法欺骗代码。
        int luaL_newmetatable(lua_State* L, const char* tName);
        void luaL_getmetatable(lua_State* L, const char* tName);
        void* luaL_checkudata(lua_State* L, int index, const char* tName);
        newmetatable函数会创建一个新的table用作元表,并将其压入栈顶,然后将这个table与注册表中的指定名称关联起来。
        getmetatable函数可以在注册表中检索与tname相关联的元表,
        luaL_checkudata 可以检查栈中指定位置上是否为一个userdata,并且是否具有与给定名称相匹配的元表。
        如果该对象不是一个userdata,或者他不具有正确的元表,将会引发一个错误。
        否则他会返回这个userdata的地址。

        int luaopen_userdatademo(lua_State* L){
            luaL_newmetatable(L, "student");
            luaL_register(L, "student", arrayFunc);
            return 1;
        }

        static int Student(lua_State* L){
            size_t iBytes = sizeof(struct StudentTag);
            struct StudentTag* pStudent;
            pStudent = (struct StudentTag*)lua_newuserdata(L, iBytes);

            luaL_getmetatable(L, "Student");
            lua_setmetatable(L, -2);
            return 1;
        }

        static int GetName(lua_State* L){
            struct StudentTag* pStudent = (struct StudentTag*)luaL_checkudata(L, 1, "student");
            lua_pushstring(L, pStudent->strName);
            return 1;
        }
    26 数组访问
        26.1 Lua中
            local metaarray = getmetatable(array.new(1))
            metaarray.__index = array.get
            metaarray.__newindex = array.set
            metaarray.__len = array.size

            a = array.new(100)
            a[10] = true --setarray
            print(a[10]) --getarray
            print(#a) --getsize
        26.2 C代码注册中修改
            static const struct luaL_Reg  arrayLib_m[]={
                {"__newindex", setarray},
                {"__index", getarray},
                {"__len", getsize},
                {"__tostring", array2string},
                {NULL, NULL}
            };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值