lua基础概要

关键字

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 = [[
          
          
            An HTML Page
          
          
            Lua
          
          
        ]]
格式化

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

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

a title

控制结构

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基础概要)