美文网首页
lua基础概要

lua基础概要

作者: xor_eax_eax | 来源:发表于2018-04-20 18:27 被阅读0次

    关键字

    and       break     do        else      elseif
    end       false     for       function  goto
    if        in        local     nil       not
    or        repeat    return    then      true
    until     while
    

    变量

    定义全局变量
    msg = "hello world"
    
    定义局部变量
    local msg = "hello world"
    

    代码注释

    行注释 --

    使用 -- 可以注释到行尾

    块注释 --[[]]

    使用 --[[xxx]] 可以注释一个代码块

    如果注释内容存在]],则需要配合=,例如--[=[会一直匹配到下一个]=]出现,]]里可以写多个=,例如--[==[会一直匹配到下一个]==].

    类型

    lua有8种类型,分别是:

    • Boolean
    • number
    • string
    • userdata
    • function
    • thread
    • table
    type函数

    使用type函数可以获取变量的类型,例如:

    type(nil) --> nil
    type(true) --> Boolean
    type("Hello world")  --> string
    type(io.stdin) --> userdata
    
    Boolean

    lua中,除了 nil 和 false 为false,其他都为true

    number

    lua5.3之后,number类型分为 integer 和 float
    通过math.type函数可以获取number的类型,例如:

    math.type(3) --> integer
    math.type(3.0)   --> float
    

    操作符

    //

    lua5.3加入了一个新的操作符,floor division
    /运算符使用是得到一个float类型的数字,哪怕是2个integer相除
    如果2个integer用//相除,会得到一个integer

    关系运算符
    • <
    • >
    • <=
    • >=
    • ==
    • ~=
    ~=

    类似其他语言的!=,和==相反.

    随机数

    random

    使用random函数可以生成一个伪随机数
    如果random不带参数,随机数分布在[0,1)中.
    如果random只带一个参数,则随机数分布在[1,n]中.
    如果random带2个参数,随机数分布在[n,n]中.

    因为是伪随机数,所以每一次执行程序,随机数都是相同的序列,如果想改变这种情况,可以设置随机数种子,一般设置时间戳为种子.

    math.randomseed

    设置当前随机数种子,例如设置当前时间戳为随机数种子:

    math.randomseed(os.time())
    

    字符串

    计算字符串的长度 #

    # 符号用来计算字符串的长度
    例如

    a = "hello"
    print(#a)             --> 5
    
    拼接字符串 ...

    ...可以用来拼接多个字符串,例如:

    "Hello " .. "World"     --> Hello World
    "result is " .. 3       --> result is 3
    10 .. 20                --> result is 1020
    
    长字符串

    如果一个字符串字面量,非常长,需要写多行,那么可以使用[[]]符号来创建长字符串.
    例如:

    page = [[
              <html>
              <head>
                <title>An HTML Page</title>
              </head>
              <body>
                <a href="http://www.lua.org">Lua</a>
              </body>
              </html>
            ]]
    
    格式化

    lua也有类似c的print函数,例如:

    string.format("x = %d  y = %d", 10, 20)     --> x = 10  y = 20
    string.format("<%s>%s</%s>", tag, title, tag)   --> <h1>a title</h1>
    

    控制结构

    if then else

    if用来测试条件,如果为true执行then语句块,否者执行else语句块

    if a < 0 then a = 0 end
    if a < b then return a else return b end
    if line > MAXLINES then
        showpage()
        line = 0 
    end
    
    while

    while用来执行循环,条件成立则执行do语句块

    local i = 1
    while a[i] do
        print(a[i])
        i=i+ 1 
    end
    
    repeat

    和while类似,但是第一次不测试条件,先执行后测试

    local line
    repeat
        line = io.read()
    until line ~= ""
    print(line)
    
    Numerical for

    for需要3个表达式,exp3可以省略,如果exp省略,则lua假设exp3每次+1

    for var = exp1, exp2, exp3 do
        something
    end
    
    break, return, goto

    break用来跳出一个循环,return用来跳出一个函数,goto可以跳到某个标签的位置,标签通过 ::xx:: 符号定义

    while some_condition do
        ::redo::
        if some_other_condition then goto continue 
        else if yet_another_condition then goto redo 
        end
        some code
        ::continue::
    end
    

    Table

    lua中,table是最核心的数据结构,table既不是值,也不是变量,而是一个对象.

    创建table
    a = {}
    k = "x"
    a[k] = 10
    a[20] = "great"
    a["x"]              --> 10
    k = 20
    a[k]                --> "great"
    
    语法糖

    t["name"] 在lua里 可以写成 t.name

    a = {}
    a.x = 10    -- same as a["x"] = 10
    a.x         --> 10
    
    构造器

    {}是一个空constructor,constructor可以初始化一个列表

    days = {"Sunday", "Monday", "Tuesday", "Wednesday",
                      "Thursday", "Friday", "Saturday"}
                      
    print(days[4])  --> Wednesday
    

    constructor 也可以初始化一个 record-like table

    a = {x = 10, y = 20}
    
    数组,列表,序列

    一个table,如果index是一个有序序列,则这个table就是一个数组.

    a = {}
    a[1] = 1
    a[2] = 1
    a[3] = 1
    a[4] = 1
    
    数组的长度

    可以和字符串一样,通过使用#来获取数组的大小

    #a      --> 4
    
    数组空洞

    如果一个table的index是一个序列,但是其中某些字段为nil,那么通过#无法计算真实的数组长度

    a = {}
    a[1] = 1
    a[2] = nil    -- does nothing, as a[2] is already nil
    a[3] = 1
    a[4] = 1
     
    #a      --> 1
    
    遍历table

    使用 pairs iterator 可以用来迭代table

    t = {10, print, x = 12, k = "hi"}
    for k, v in pairs(t) do
        print(k, v)
    end  
     
    --> 1   10
    --> k   hi
    --> 2   function: 0x420610
    --> x   12
    

    pairs iterator是无序的,如果想要保持table赋值的顺序,可以使用ipairs

    t = {10, print, 12, "hi"}
    for k, v in ipairs(t) do
        print(k, v)
    end  
     
    --> 1   10
    --> 2   function: 0x420610
    --> 3   12
    --> 4   hi
    

    如果table是一个数组,则可以通过#符号来遍历

    t = {10, print, 12, "hi"}
    for k = 1, #t do
        print(k, t[k])
    end
     
    --> 1   10
    --> 2   function: 0x420610
    --> 3   12
    --> 4   hi
    
    Safe Navigation

    如果我们想调用table的函数,首先得校验table是否存在.如果table嵌套比较多写起来比较丑,而且麻烦
    例如:

    zip = company and company.director and
              company.director.address and
                    company.director.address.zipcode
    

    使用 or {} 可以简化这种操作

    zip = (((company or {}).director or {}).address or {}).zipcode
    

    或者更简洁高效的写法

    E = {}     -- can be reused in other similar expressions
    zip = (((company or E).director or E).address or E).zipcode
    

    函数

    省略括号

    如果函数只有一个参数,可以省略掉(),例如:

    print "Hello World"     <-->     print("Hello World")
    dofile 'a.lua'          <-->     dofile ('a.lua')
    print [[a multi-line    <-->     print([[a multi-line
            message]]                       message]])
    type{}                  <-->     type({})
    
    实参和形参可以不对称

    如果实参多余形参,则抛弃掉多余的实参,如果实参少于形参,则形参初始化为nil

    function f (a, b) print(a, b) end  
      
    f()             --> nil    nil
    f(3)            --> nil    nil
    f(3, 4)         --> 3      4
    f(3, 4, 5)      --> 3      4      (5 is discarded)
    
    多返回值

    一个函数可以有多个返回值

    function maximum (a)
        local mi = 1
        local m = a[mi]
        for i = 1, #a do
            if a[i] > m then
                mi = i; m = a[i]
            end 
        end
        return m, mi
    end
    -- index of the maximum value
    -- maximum value
    -- return the maximum and its index
    
    print(maximum({8,10,23,12,5}))     --> 23   3
    

    多返回值可以初始化一个table

    print(maximum({8,10,23,12,5}))     --> 23   3       -- returns 2 results
     
    t = {foo2()}        -- t = {"a", "b"}
    
    可变参数

    函数定义可以通过 ... 符号来声明可变参数

    function add (...)
        local s = 0
        for _, v in ipairs{...} do
            s=s+ v 
        end
        return s 
    end
     
    print(add(3, 4, 10, 25, 12))    --> 54
    

    ... 甚至用来初始化变量和作为返回值

    function foo (...)
        local a, b, c = ...
        
    function id (...) return ... end
    
    table.pack函数

    聚合 ... 可以使用{...},也可以使用table.pack函数,{...}有可能存在空洞,而table.pack则可以检测到nil

    function nonils (...)
        local arg = table.pack(...)
        for i = 1, arg.n do
          if arg[i] == nil then 
            return false 
          end
        end
        return true
    end
     
    print(nonils(2,3,nil))      --> false
    print(nonils(2,3))          --> true
    print(nonils())             --> true
    print(nonils(nil))          --> false
    
    select函数

    select函数接收一个固定参数 selector,加一个可变参数,如果 selector 为n,则返回这个可变参数中n之后的参数,如果 selector#,则返回可变参数的个数
    例如:

    print(select(1, "a", "b", "c"))     --> a    b    c
    print(select(2, "a", "b", "c"))     --> b    c
    print(select(3, "a", "b", "c"))     --> c
    print(select("#", "a", "b", "c"))   --> 3
    

    通过select函数来遍历可变参数

    function add (...)
        local s = 0
        for i = 1, select("#", ...) do
          s = s + select(i, ...)
        end
        return s 
    end
    
    table.unpack函数

    跟table.pack函数相反,跟table.unpack函数是将一个table拆分

    print(table.unpack{10,20,30})    --> 10   20   30
    a,b = table.unpack{10,20,30}     -- a=10, b=20, 30 is discarded
    

    table.unpack函数还可以接收额外的2个参数

    print(table.unpack({"Sun", "Mon", "Tue", "Wed"}, 2, 3))
                --> Mon    Tue
    

    Simple io模型

    简单io模型假设存在 current input stream 和一个 current output stream
    默认的current input stream 为stdin,默认的 current output stream 为stdout,io.read函数可以用来读取流里面的内容

    current streams有 io.input 和 io.output 两个函数用来获取输入输出流,
    例如io.input接收一个文件名,用来打开一个文件:

    io.input(filename)
    
    io.write函数

    io.write可以接收任意个参数,并将它们写到current output stream

    io.write(a..b..c)
    

    一种更高效的写法(不拼接字符串)

    io.write(a, b, c)
    
    io.read函数

    io.read函数从current stream中读取string,参数可以控制读取的内容

    参数 内容
    "a" reads the whole file
    "l" reads the next line (dropping the newline)
    "L" reads the next line (keeping the newline)
    "n" reads a number
    num reads num characters as a string
    t = io.read("a")                    -- read the whole file
    t = string.gsub(t, "bad", "good")   -- do the job
    io.write(t)                         -- write the file
    

    Complete I/O 模型

    如果需要同时写入多个文件,则需要Complete I/O 模型,io.open用于打开一个文件,类似c里面的open
    io.open函数接收一个文件名,后面加一个字符串 mode 参数,类似c,mode可以为

    • "r" 读
    • "w" 写
    • "a" 附加

    如果文件不存,或者存在异常,在则返回nil

    print(io.open("non-existent-file", "r"))
    --> nil     non-existent-file: No such file or directory    2
     
    print(io.open("/etc/passwd", "w"))
    --> nil     /etc/passwd: Permission denied  13
    

    通常检查错误是通过assert断言

    local f = assert(io.open(filename, mode))
    

    打开文件之后可以使用read和write读取或者写入,但是是在一个stream对象上操作
    例如

    local f = assert(io.open(filename, "r"))
    local t = f:read("a")
    f:close()
    

    实际上io.read是io.input():read的简写,io.write是io.output():write的简写

    预设的stream对象
    • io.stdin
    • io.stdout
    • io.stderr

    直接使用预设的stream对象

    io.stderr:write(message)
    

    如果想更改current stream

    local temp = io.input() io.input("newinput")    -- save current stream
    do something with new input     -- open a new current stream
    io.input():close()      -- close current stream
    io.input(temp)      -- restore previous current stream
    
    io.lines函数

    io.lines函数返回一个重复读取文件的iterator,lua5.2之后,io.lines和io.read接收同样的参数,例如

    for block in io.input():lines(2^13) do
        io.write(block)
    end
    

    执行系统命令

    os.execute函数

    os.execute可以执行系统命令,例如创建文件夹:

    function createDir (dirname)
        os.execute("mkdir " .. dirname)
    end
    
    os.popen函数

    os.popen功能和os.execute类似,但是可以获取命令的返回内容

    -- for POSIX systems, use 'ls' instead of 'dir'
    local f = io.popen("dir /B", "r")
    local dir = {}
    for entry in f:lines() do
        dir[#dir + 1] = entry
    end

    相关文章

      网友评论

          本文标题:lua基础概要

          本文链接:https://www.haomeiwen.com/subject/nsuzkftx.html