lua-快速入门学习

安装

centos环境:

yum install lua

windows:

window 下你可以使用一个叫 “SciTE” 的 IDE环 境来执行 lua 程序,下载地址为:

  • Github 下载地址:https://github.com/rjpcomputing/luaforwindows/releases
  • Google Code下载地址 : https://code.google.com/p/luaforwindows/downloads/list

双击安装后即可在该环境下编写 Lua 程序并运行。

你也可以使用 Lua 官方推荐的方法使用 LuaDist:http://luadist.org/

Hello World

创建一个文件为 helloworld.lua内容是:print("hello qingchen")

[root@qingchen lua]# lua helloworld.lua 
hello qingchen

基本语法

注释

单行:

-- 注释

多行

--[[
 多行注释
 多行注释
 --]]

变量定义

Lua 标示符用于定义一个变量,函数获取其他用户定义的项。标示符以一个字母 A 到 Z 或 a 到 z 或下划线 _ 开头后加上 0 个或多个字母,下划线,数字(0 到 9)。

最好不要使用下划线加大写字母的标示符,因为Lua的保留字也是这样的。

Lua 不允许使用特殊字符如 @, $, 和 % 来定义标示符。

Lua 是一个区分大小写的编程语言。因此在 Lua 中 Qingchenqingchen 是两个不同的标示符。
以下列出了一些正确的标示符:

name         version      abc     move_name    a_123
name50       _temp        j       zxc9527        retHat

关键字

and

break

do

else

elseif

end

false

for

function

if

in

local

nil

not

or

repeat

return

then

true

until

while

goto

全局变量

lua默认情况下都是全局变量

全局变量不需要声明,给一个变量赋值后即创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil。

> print(b)
nil
> b=10
> print(b)
10
>

删除一个全局变量,只需要将变量赋值为nil。

b = nil
print(b)      --> nil

数据类型

Lua 是动态类型语言,变量不要类型定义,只需要为变量赋值。 值可以存储在变量中,作为参数传递或结果返回。

Lua 中有 8 个基本类型分别为:nil、boolean、number、string、userdata、function、thread 和 table。

数据类型

描述

nil

只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)

boolean

包含两个值:false和true

number

表示双精度类型的实浮点数

string

字符串由一对双引号或单引号来表示

function

由 C 或 Lua 编写的函数

userdata

表示任意存储在变量中的C数据结构

thread

表示执行的独立线路,用于执行协同程序

table

其实是个"关联数组",数组的索引可以是数字、字符串或表类型。通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。

print(type("Hello world"))      --> string
print(type(10.4*3))             --> number
print(type(print))              --> function
print(type(type))               --> function
print(type(true))               --> boolean
print(type(nil))                --> nil
print(type(type(X)))            --> string

nil(空)

nil 类型表示一种没有任何有效值,它只有一个值 – nil,打印一个没有赋值的变量,便会输出: nil

对于全局变量和 table,nil 还有一个"删除"作用,给全局变量或者 table 表里的变量赋一个 nil 值,等同于把它们删掉

nil 作比较时应该加上双引号 ":

> type(X)
nil
> type(X)==nil
false
> type(X)=="nil"
true
>

type(X)==nil 结果为 false 的原因是 type(X) 实质是返回的 "nil" 字符串,是一个 string 类型:
type(type(X))==string

boolean(布尔)

boolean 类型只有两个可选值:true(真) 和 false(假),Lua 把 false 和 nil 看作是 false,其他的都为 true,数字 0 也是 true

number(数字)

Lua 默认只有一种 number 类型 – double(双精度)类型(默认类型可以修改 luaconf.h 里的定义)

string(字符串)

字符串由一对双引号或单引号来表示。

也可以用 2 个方括号 “[[]]” 来表示"一块"字符串。

html = [[
<html>
<head></head>
<body>
    <a href="http://www.zjl.com/">周杰伦</a>
</body>
</html>
]]
print(html)

在对一个数字字符串上进行算术操作时,Lua 会尝试将这个数字字符串转成一个数字:

> print("2" + 6)
8.0
> print("2" + "6")
8.0
> print("2 + 6")
2 + 6
> print("-2e2" * "6")
-1200.0
> print("error" + 1)
stdin:1: attempt to perform arithmetic on a string value
stack traceback:
        stdin:1: in main chunk
        [C]: in ?
>
-- 字符串连接使用的是 .. 
> print("a" .. 'b')
ab
> print(157 .. 428)
157428
> 
-- 使用 # 来计算字符串的长度,放在字符串前面
> len = "www.zjl.com"
> print(#len)
11
> print(#"www.zjl.com")
11
>

table(表)

在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。也可以在表里添加一些数据,直接初始化表

-- 创建一个空的 table
local tbl1 = {}
 
-- 直接初始表
local tbl2 = {"apple", "pear", "orange", "grape"}

-- table_test.lua 脚本文件
a = {}
a["key"] = "value"
key = 10
a[key] = 22
a[key] = a[key] + 11
for k, v in pairs(a) do
    print(k .. " : " .. v)
end

-- 输出
$ lua table_test.lua 
key : value
10 : 33

-- 不同于其他语言的数组把 0 作为数组的初始索引,在 Lua 里表的默认初始索引一般以 1 开始。

-- table_test2.lua 脚本文件
local tbl = {"apple", "pear", "orange", "grape"}
for key, val in pairs(tbl) do
    print("Key", key)
end

-- 输出
$ lua table_test2.lua 
Key    1
Key    2
Key    3
Key    4

-- table 不会固定长度大小,有新数据添加时 table 长度会自动增长,没初始的 table 都是 nil。

-- table_test3.lua 脚本文件
a3 = {}
for i = 1, 10 do
    a3[i] = i
end
a3["key"] = "val"
print(a3["key"])
print(a3["none"])

-- 输出
$ lua table_test3.lua 
val
nil

function(函数)

在 Lua 中,函数是被看作是"第一类值(First-Class Value)",函数可以存在变量里

-- function_test.lua 脚本文件
function factorial1(n)
    if n == 0 then
        return 1
    else
        return n * factorial1(n - 1)
    end
end
print(factorial1(5))
factorial2 = factorial1
print(factorial2(5))

-- 输出
$ lua function_test.lua 
120
120

-- function 可以以匿名函数(anonymous function)的方式通过参数传递
-- function_test2.lua 脚本文件
function testFun(tab,fun)
        for k ,v in pairs(tab) do
                print(fun(k,v));
        end
end


tab={key1="val1",key2="val2"};
testFun(tab,
function(key,val)--匿名函数
        return key.."="..val;
end
);

-- 输出
$ lua function_test2.lua 
key1 = val1
key2 = val2

thread(线程)

在 Lua 里,最主要的线程是协同程序(coroutine)。它跟线程(thread)差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西。

线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停。

userdata(自定义类型)

userdata 是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。

Lua变量

Lua 变量有三种类型:全局变量、局部变量、表中的域。

Lua 中的变量全是全局变量,哪怕是语句块或是函数里,除非用 local 显式声明为局部变量。

局部变量的作用域为从声明位置开始到所在语句块结束。

变量的默认值均为 nil。

-- test.lua 文件脚本
a = 5               -- 全局变量
local b = 5         -- 局部变量

function joke()
    c = 5           -- 全局变量
    local d = 6     -- 局部变量
end

joke()
print(c,d)          --> 5 nil

do
    local a = 6     -- 局部变量
    b = 6           -- 对局部变量重新赋值
    print(a,b);     --> 6 6
end

print(a,b)      --> 5 6

赋值是改变一个变量的值和改变表域的最基本的方法

Lua 可以对多个变量同时赋值,变量列表和值列表的各个元素用逗号分开,赋值语句右边的值会依次赋给左边的变量。

a, b = 10, 2*x       <-->       a=10; b=2*x

遇到赋值语句Lua会先计算右边所有的值然后再执行赋值操作,所以我们可以这样进行交换变量的值

x, y = y, x                     -- swap 'x' for 'y'
a[i], a[j] = a[j], a[i]         -- swap 'a[i]' for 'a[j]'

当变量个数和值的个数不一致时,Lua会一直以变量个数为基础采取以下策略:

a. 变量个数 > 值的个数             按变量个数补足nil
b. 变量个数 < 值的个数             多余的值会被忽略
a, b = f()

f()返回两个值,第一个赋给a,第二个赋给b。

应该尽可能的使用局部变量,有两个好处:

  1. 避免命名冲突。
  2. 访问局部变量的速度比全局变量更快。

索引

对 table 的索引使用方括号 []。Lua 也提供了 . 操作。

t[i]
t.i                 -- 当索引为字符串类型时的一种简化写法
gettable_event(t,i) -- 采用索引访问本质上是一个类似这样的函数调用

Lua循环

while 循环

while(condition)
do
   statements
end

for 循环

Lua 编程语言中 for语句有两大类:

  • 数值for循环
  • 泛型for循环
数值for循环

Lua 编程语言中数值 for 循环语法格式:

for var=exp1,exp2,exp3 do  
    <执行体>  
end  

-- var 从 exp1 变化到 exp2,每次变化以 exp3 为步长递增 var,并执行一次 "执行体"。exp3 是可选的,如果不指定,默认为1。
-- for的三个表达式在循环开始前一次性求值,以后不再进行求值。比如上面的f(x)只会在循环开始前执行一次,其结果用在后面的循环中。
泛型for循环

泛型 for 循环通过一个迭代器函数来遍历所有值,类似 java 中的 foreach 语句。

Lua 编程语言中泛型 for 循环语法格式:

--打印数组a的所有值  
a = {"one", "two", "three"}
for i, v in ipairs(a) do
    print(i, v)
end 
-- i是数组索引值,v是对应索引的数组元素值。ipairs是Lua提供的一个迭代器函数,用来迭代数组。

repeat…until 循环

repeat…until 循环的条件语句在当前循环结束后判断,在条件进行判断前循环体都会执行一次

repeat
   statements
until( condition )

循环嵌套

Lua 编程语言中 for 循环嵌套语法格式:

for init,max/min value, increment
do
   for init,max/min value, increment
   do
      statements
   end
   statements
end

Lua 编程语言中 while 循环嵌套语法格式:

while(condition)
do
   while(condition)
   do
      statements
   end
   statements
end

Lua 编程语言中 repeat…until 循环嵌套语法格式:

repeat
   statements
   repeat
      statements
   until( condition )
until( condition )

Lua 流程控制

if

if(布尔表达式)
then
   --[ 在布尔表达式为 true 时执行的语句 --]
end
if(布尔表达式)
then
   --[ 布尔表达式为 true 时执行该语句块 --]
else
   --[ 布尔表达式为 false 时执行该语句块 --]
end
if( 布尔表达式 1)
then
   --[ 布尔表达式 1 为 true 时执行该语句块 --]
   if(布尔表达式 2)
   then
      --[ 布尔表达式 2 为 true 时执行该语句块 --]
   end
end

Lua 函数

在Lua中,函数是对语句和表达式进行抽象的主要方法。既可以用来处理一些特殊的工作,也可以用来计算一些值。

Lua 提供了许多的内建函数,你可以很方便的在程序中调用它们,如print()函数可以将传入的参数打印在控制台上。

Lua 函数主要有两种用途:

  1. 完成指定的任务,这种情况下函数作为调用语句使用;
  2. 计算并返回值,这种情况下函数作为赋值语句的表达式使用。

函数定义

Lua 编程语言函数定义格式如下:

optional_function_scope function function_name( argument1, argument2, argument3..., argumentn)
    function_body
    return result_params_comma_separated
end

--[[
optional_function_scope: 该参数是可选的制定函数是全局函数还是局部函数,未设置该参数默认为全局函数,如果你需要设置函数为局部函数需要使用关键字 local。

function_name: 指定函数名称。

argument1, argument2, argument3..., argumentn: 函数参数,多个参数以逗号隔开,函数也可以不带参数。

function_body: 函数体,函数中需要执行的代码语句块。

result_params_comma_separated: 函数返回值,Lua语言函数可以返回多个值,每个值以逗号隔开。
--]]

-- Lua 函数可以接受可变数目的参数,和 C 语言类似,在函数参数列表中使用三点 ... 表示函数有可变的参数。
function add(...)  
local s = 0  
  for i, v in ipairs{...} do   --> {...} 表示一个由所有变长参数构成的数组  
    s = s + v  
  end  
  return s  
end  
print(add(3,4,5,6,7))  --->25

-- 通过 select("#",...) 来获取可变参数的数量

-- 有时候可能需要几个固定参数加上可变参数,固定参数必须放在变长参数之前

function fwrite(fmt, ...)  ---> 固定的参数fmt
    return io.write(string.format(fmt, ...))    
end

--[[
通常在遍历变长参数的时候只需要使用 {…},然而变长参数可能会包含一些 nil,那么就可以用 select 函数来访问变长参数了:select('#', …) 或者 select(n, …)

select('#', …) 返回可变参数的长度。
select(n, …) 用于返回从起点 n 开始到结束位置的所有参数列表。
调用 select 时,必须传入一个固定实参 selector(选择开关) 和一系列变长参数。如果 selector 为数字 n,那么 select 返回参数列表中从索引 n 开始到结束位置的所有参数列表,否则只能为字符串 #,这样 select 返回变长参数的总数。
]] 

function f(...)
    a = select(3,...)  -->从第三个位置开始,变量 a 对应右边变量列表的第一个参数
    print (a)
    print (select(3,...)) -->打印所有列表参数
end

f(0,1,2,3,4,5)

Lua 运算符

算术

a = 21
b = 10
c = a + b
print("Line 1 - c 的值为 ", c ) -- 31
c = a - b
print("Line 2 - c 的值为 ", c ) -- 11
c = a * b
print("Line 3 - c 的值为 ", c ) -- 210
c = a / b
print("Line 4 - c 的值为 ", c ) -- 2.1
c = a % b
print("Line 5 - c 的值为 ", c ) -- 1
c = a^2
print("Line 6 - c 的值为 ", c ) -- 441
c = -a
print("Line 7 - c 的值为 ", c ) -- -21

-- / 用作除法运算,计算结果包含小数部分,// 用作整除运算,计算结果不包含小数部分
a = 5
b = 2
print("除法运算 - a/b 的值为 ", a / b ) -- 2.5
print("整除运算 - a//b 的值为 ", a // b ) -- 2

关系

操作符

描述

实例

==

等于,检测两个值是否相等,相等返回 true,否则返回 false

(A == B) 为 false。

~=

不等于,检测两个值是否相等,不相等返回 true,否则返回 false

(A ~= B) 为 true。

>

大于,如果左边的值大于右边的值,返回 true,否则返回 false

(A > B) 为 false。

<

小于,如果左边的值大于右边的值,返回 false,否则返回 true

(A < B) 为 true。

>=

大于等于,如果左边的值大于等于右边的值,返回 true,否则返回 false

(A >= B) 返回 false。

<=

小于等于, 如果左边的值小于等于右边的值,返回 true,否则返回 false

(A <= B) 返回 true。

逻辑

操作符

描述

实例

and

逻辑与操作符。 若 A 为 false,则返回 A,否则返回 B。

(A and B) 为 false。

or

逻辑或操作符。 若 A 为 true,则返回 A,否则返回 B。

(A or B) 为 true。

not

逻辑非操作符。与逻辑运算结果相反,如果条件为 true,逻辑非为 false。

not(A and B) 为 true。

其他

操作符

描述

实例


连接两个字符串

a…b ,其中 a 为 "Hello " , b 为 “World”, 输出结果为 “Hello World”。

#

一元运算符,返回字符串或表的长度。

#“Hello” 返回 5

Lua 字符串

-- 字符串方法
string.upper(argument):
-- 字符串全部转为大写字母。
string.lower(argument):
-- 字符串全部转为小写字母。
string.gsub(mainString,findString,replaceString,num)
-- 在字符串中替换。mainString 为要操作的字符串, findString 为被替换的字符,replaceString 要替换的字符,num 替换次数
string.find (str, substr, [init, [plain]])
--[[在一个指定的目标字符串 str 中搜索指定的内容 substr,如果找到了一个匹配的子串,就会返回这个子串的起始索引和结束索引,不存在则返回 nil。
init 指定了搜索的起始位置,默认为 1,可以一个负数,表示从后往前数的字符个数。
plain 表示是否使用简单模式,默认为 false,true 只做简单的查找子串的操作,false 表示使用使用正则模式匹配。]]
string.reverse(arg)
-- 字符串反转
string.format(...)
-- 返回一个类似printf的格式化字符串 string.format("the value is:%d",4) 输出: the value is:4
..
-- 链接两个字符串
> print("www.runoob.".."com")
www.runoob.com

等等在此不再介绍:参考菜鸟教程:https://www.runoob.com/lua/lua-strings.html

Lua 数组

数组比较简单不做详细介绍

-- 初始化数组
array = {}
for i=1,3 do
   array[i] = {}
      for j=1,3 do
         array[i][j] = i*j
      end
end

-- 访问数组
for i=1,3 do
   for j=1,3 do
      print(array[i][j])
   end
end

Lua 迭代器

泛型 for 迭代器

array = {"Google", "Runoob"}

for key,value in ipairs(array)
do
   print(key, value)
end

无状态的迭代器

function square(iteratorMaxCount,currentNumber)
   if currentNumber<iteratorMaxCount
   then
      currentNumber = currentNumber+1
   return currentNumber, currentNumber*currentNumber
   end
end

for i,n in square,3,0
do
   print(i,n)
end

-- 输出
1    1
2    4
3    9

Lua table(表)

table 是 Lua 的一种数据结构用来帮助我们创建不同的数据类型,如:数组、字典等。

Lua table 使用关联型数组,你可以用任意类型的值来作数组的索引,但这个值不能是 nil。

Lua table 是不固定大小的,你可以根据自己需要进行扩容。

Lua也是通过table来解决模块(module)、包(package)和对象(Object)的。 例如string.format表示使用"format"来索引table string。

构建表

-- 初始化表
mytable = {}

-- 指定值
mytable[1]= "Lua"

-- 移除引用
mytable = nil
-- lua 垃圾回收会释放内存

-- 当我们为 table a 并设置元素,然后将 a 赋值给 b,则 a 与 b 都指向同一个内存。如果 a 设置为 nil ,则 b 同样能访问 table 的元素。如果没有指定的变量指向a,Lua的垃圾回收机制会清理相对应的内存。

Lua 模块与包

Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行。

-- 文件名为 module.lua
-- 定义一个名为 module 的模块
module = {}
 
-- 定义一个常量
module.constant = "这是一个常量"
 
-- 定义一个函数
function module.func1()
    io.write("这是一个公有函数!\n")
end
 
local function func2()
    print("这是一个私有函数!")
end
 
function module.func3()
    func2()
end
 
return module

require 函数

require的函数用来加载模块。

require("<模块名>")

初学到此止步了(后面的看起来很复杂以后再学吧)


ua"

– 移除引用
mytable = nil
– lua 垃圾回收会释放内存

– 当我们为 table a 并设置元素,然后将 a 赋值给 b,则 a 与 b 都指向同一个内存。如果 a 设置为 nil ,则 b 同样能访问 table 的元素。如果没有指定的变量指向a,Lua的垃圾回收机制会清理相对应的内存。

## Lua 模块与包

Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行。

```lua
-- 文件名为 module.lua
-- 定义一个名为 module 的模块
module = {}
 
-- 定义一个常量
module.constant = "这是一个常量"
 
-- 定义一个函数
function module.func1()
    io.write("这是一个公有函数!\n")
end
 
local function func2()
    print("这是一个私有函数!")
end
 
function module.func3()
    func2()
end
 
return module

require 函数

require的函数用来加载模块。

require("<模块名>")

GG

初学到此止步了(后面的看起来很复杂以后再学吧)