Fork me on GitHub

Lua基础

Lua基础

1.hello world

print("hello world")

2.注释

  • 单行注释
 --
  • 多行注释
--[[
多行注释
--]]

3.标示符

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

4.关键词

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

5.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 Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字、字符串或表类型。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。
  • 对于全局变量和table,nil还有一个"删除"作用。给全局变量或者table表里的变量赋一个nil值,等同于把它们删除,执行下面代码就知道。
tab1 = { key1 = "val1", key2 = "val2", "val3"}
for k,v in pairs(tab1) do
	print(k .. " - " .. v)
end
--[[
1 - val3
key1 - val1
key2 - val2
--]]

tab1.key1 = nil
for k, v in pairs(tab1) do
	print(k .. " - " .. v)
end

--[[
1 - val3
key2 - val2
--]]
  • 实例
> print(type(true))
boolean
> print(type(flase))
nil
> print(type(nil))
nil

5.1 boolean 布尔

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

  • 实例

if false or nil then
	print("至少有一个true")
else
	print("false 和 nil 都为 false")
end

if 0 then
	print("数字 0 是 true")
else
	print("数字 0 是 true")
end

-- false 和 nil 都为 false
-- 数字 0 是 true

5.2 number 数字

  • Lua默认只有一种number类型。(double双精度类型),默认类型可以修改 luaconf h里的定义,以下几种写法都被看做是number类型。
  • 实例
> print(type(2))
number
> print(type(2.2))
number
> print(type(0.2))
number
> print(type(0.2e-1))
number
> print(type(7.82532323e-6))
number

5.3 String字符串

  • 字符串由一对双引号或单引号来表示
string1 = "this is string1"
print(string1)
  • 示例
html = [[
<html>
<head></head>
<body>
	<a href="http://www.runoob.com/">cainian</a>
</body>
</html>
]]
print(html)
--[[
<html>
<head></head>
<body>
        <a href="http://www.runoob.com/">cainian</a>
</body>
</html>
--]]
  • 在对一个数字字符串上进行算数操作时,Lua会尝试将这个数字字符串转成一个数字。
num = "2" + 13
print(type(num))
print("2" + 6)
print("2" + 11)
print("-2e2" * "6")
print("a" .. "b")
print(157 .. 429)

--[[
number
8
13
-1200
ab
157429
--]]
  • len计算长度
len_str = "www.baidu.com"
print(#len_str)
print(#"www.baidu.com")
--[[
13
13
--]]

5.4 table (表)

  • 在lua里,table的创建时通过“构造表达式“来完成,最简单构造表达式是{},用来创建一个空表,也可以在表里添加一些数据,直接初始化表。
-- 创建一个空的 table
local tbl1 = {}
-- 直接初始表
local tbl2 = {"apple","pear","orange", "grape"}
-- table: 00B09770   地址
print(tbl2)
  • 实例
a = {}
a["key"] = "value"
key = 10
-- 创建key, value
a[key] = 22
-- 给key赋值value
a[key] = a[key] + 11
for k, v in pairs(a) do
	print(k .. " :  " .. v)
end
--[[
key :  value
10 :  33
--]]
  • 示例
local tb1 = {"apple", "pear", "orange", "grape"}
for key, val in pairs(tb1) do
	print("key", key, val)
end
--[[
key     1       apple
key     2       pear
key     3       orange
key     4       grape
--]]
  • 实例
a3 = {}
for i = 1,10 do
	a3[i] = i
end
print(a3)
a3["key"] = "val"
print(a3["key"])
print(a3["none"])
--[[
table: 00A69518
val
nil
--]]

5.5 function 函数

  • 在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))
-- 120
-- 120
  • 示例:
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
);
--[[
key1=val1
key2=val2
--]]

5.6 thrad (线程)

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

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

5.7 userdata 自定义类型

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

6.Lua变量

  • Lua变量有三种类型:全局,局部,表中域。
a = 5--全局变量
local b = 5--局部变量
function joke()
	c = 5--全局变量
	local d = 6--局部变量
end

joke()

print(c,d)-- 5 nil

  • 示例
do
	local a = 5--局部变量
	b = 6
	print(a, b);-- 5   6
end
-- 5       6
  • 赋值语句
a = "hello" .. " world"
print(a)
-- hello world
x = 8
a, b = 10, 2*x
print(a,b)
-- 10 16


a, b, c = 0, 1
print(a,b,c) -- 0       1       nil
  • 索引
    • 对table的索引使用方括号[],Lua也提供了,操作。
t = {"apple","pear","orange", "grape"}
i = 3
print(t[i])
-- orange
site = {}

site["key"] = "www.runoob.com"
site["key2"] = "woqu"
print(site["key"])
print(site.key)
print(site.key2)
--[[
www.runoob.com
www.runoob.com
woqu
--]]

7.循环控制

  • 死循环
while( true )
do
	print("循环死循环...")
end

--[[
循环死循环...
循环死循环...
循环死循环...
循环死循环...
循环死循环...
循环死循环...
循环死循环...
...
--]]

  • lua没有continue,可以使用类似下面方法
for i = 10, 1, -1 do
	repeat
		if i == 5 then
			print("continue code here")
			break
		end
		print(i, "loop code hera")
	until true
end
--[[

10      loop code hera
9       loop code hera
8       loop code hera
7       loop code hera
6       loop code hera
continue code here
4       loop code hera
3       loop code hera
2       loop code hera
1       loop code hera
--]]

8.Lua流程控制

if (0)
then
	print("0 为 true")
end
-- 0 为 true
  • if条件
if(布尔表达式)
then
   --[ 布尔表达式为 true 时执行该语句块 --]
else
   --[ 布尔表达式为 false 时执行该语句块 --]
end
a = 100
if (a < 20)
then
	print("a 小于 20")
else
	print("a 大于 20")
end
print("a 的值为:", a)
-- a 大于 20
-- a 的值为:       100
  • if...elseif...else语句
if( 布尔表达式 1)
then
   --[ 在布尔表达式 1 为 true 时执行该语句块 --]

elseif( 布尔表达式 2)
then
   --[ 在布尔表达式 2 为 true 时执行该语句块 --]

elseif( 布尔表达式 3)
then
   --[ 在布尔表达式 3 为 true 时执行该语句块 --]
else 
   --[ 如果以上布尔表达式都不为 true 则执行该语句块 --]
end
  • 实例
a = 100

if (a == 10)
then
	print("a 的值为10")
elseif( a == 20)
then
	print("a 的值为20")
elseif( a==30)
then
	print("a 的值为 30")
else
	print("没有匹配 a的值")
end
print("a 的真实值为:", a)
-- 没有匹配 a的值
-- a 的真实值为:   100

9.函数

  • 在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... 函数参数,多个参数以逗号隔开,函数也可以不带参数。
-- function_body:函数体,执行代码块
-- result_params_comma_separated: 函数返回值,Lua语言函数可以返回多个值,每个值以逗号隔开
  • 实例
function max(num1,num2)
	if (num1 > num2) then
		result = num1;
	else
		result = num2;
	end

	return result;
end
print("最大的值为:",max(10,5))

lua max_num.lua
  • 函数做为参数传递给函数:
myprint = function(param)
	print("这是打印函数 - ##",param, "##")
end

function add(num1,num2,functionPrint)
	result = num1 + num2
	functionPrint(result)
end

-- 执行myprint函数
myprint(10)

-- 将myprint传入add函数中
add(3,4,myprint)


--[[
这是打印函数 - ##       10      ##
这是打印函数 - ##       7       ##
--]]

  • 多个返回值
    • 比如通过string find 返回匹配字符串开始和结束的下标。如果不存在则返回nil
s,e = string.find("www.baidu.com","baidu")
print(s,e)

-- 5       9
-- 求最大值索引和值
unction maximum (a)
    local mi = 1
	local m = a[mi]
	for i,val in ipairs(a) do
		if val > m then
			mi = i
			m = val
		end
	end
	return m,mi
end
print(maximum({5,10,15,30,6,1}))
-- 30      4
  • 可变参数
    • 接收可变数目参数。类似于C语言,通过三个点表示...
function add(...)
	local s = 0
	local arg = {...}
	for i, v in ipairs{...} do
		s = s + v
	end
	print("总共传入:" .. #arg .. " 个")
	return s

end
print(add(4,5,6,10,2,3,11))
-- 总共传入:7 个
-- 41
  • 练习
do
	function foo(...)
		for i = 1,select('#', ...) do
			-- 读取参数
			local arg = select(i, ...);
			print("arg",arg);
		end
	end

	foo(1,2,3,4);
end、
--[[
arg     1
arg     2
arg     3
arg     4
--]]

10.Lua运算符

  • Lua运算符是一个特殊符号,用于告诉解释器执行特定数学或逻辑运算。
    • 算数运算符,关系运算符,逻辑运算符,其他运算符。

10.1算数运算符

+加
-减
*乘
/除
%取余
^幂
-负号
  • 示例
a = 25
b = 10
print("a-b=",a-b)
print("a+b=",a+b)
print("a*b=",a*b)
print("a/b=",a/b)
print("a%b=",a%b)
print("a^b=",a^b)
print("-b=",-b)
--[[
a-b=    15
a+b=    35
a*b=    250
a/b=    2.5
a%b=    5
a^b=    95367431640625
-b=     -10
--]]

10.2关系运算符

==等于
~=不等于
>大于
<小于
>=大于等于
<=小于等于
  • 示例
a = 25
b = 10

if (a == b)
then
	print("a等于b")
elseif (a > b)
then
	print("a大于b")
elseif (a < b)
then
	print("a小于b")
end

if (a ~= b)
then
	print("a不等于b")
end

10.3逻辑运算符

and 与
or 或
not 非
  • 示例
a = true
b = true

if (a and b)
then
	print("a and b 为真")
end

if (a or b)
then
	print("a or b 为真")
end

if (not (a and b))
then
	print("not (a and b )为真")

end
-- a and b 为真
-- a or b 为真

10.4其他运算符

  • 通过以下实例来理解运算符与计算表或字符串长度运算符的应用。
a = "Hello "
b = "world"

print("连接a,b:", a..b )
print("a的长度:",#a )
print("beautiful的长度:",#"beautiful" )
-- a的长度:        6
-- beautiful的长度:        9

10.5运算符优先级

  • 从高到低排序
^
not
* /
+ -
..
< > <= >= ~= ==
and
or
  • 示例
a + i < b/2 + 1       (a + i) < ((b/2)+1)
5 + x^2*8		5+((x^2)*8)
a < y and y <=z    (a < y) and (y <= z)
-x^2	-(x^2)

11.Lua字符串

  • 字符串种类分为三种,单引号,双引号,[[]] .
s1 = "Lua1"
print("s1",s1)
s2 = 'Lua2'
print("s2",s2)
s3 = [["Lua3"]]
print("s3",s3)

-- s1      Lua1
-- s2      Lua2
-- s3      "Lua3"

11.1转义字符

\a	BEl
\b	退格BS
\f	换页FF
\n	换行LF
\r	回车CR
\t	水平制表HT
\v	垂直制表VT
\\	代表反斜杠字符'\'
\'	代表一个单引号
\"	代表一个双引号
\0	空字符
\ddd	1-3位八进制数,任意字符
\xhh	1-2位十六进制任意字符

11.2字符串操作

  • 字符串方法
string.upper(argument) 字符串全转大写
string.lower(argument) 字符串全转小写
string.gsub(mainString,findString,replaceString.num) 在字符串中替换
string.find(str,substr,[init,[end]])  在指定目标字符串搜索指定内容返回具体位置,不存在返回nil
string.reverse(arg)	字符串反转
string.format(...)	返回一个类似printf格式化字符串
string.char(arg)和string.byte(arg[,int]) char将整型字符串转成字符并连接,byte转换字符为整数值。
string.len(arg)	计算字符串长度
string.rep(string,n)	返回字符串string的n个拷贝
..	链接2个字符串
string.gmatch(str,pattern)	返回一个迭代器函数,每一次调用这个函数,返回一个在字符串 str 找到的下一个符合 pattern 描述的子串。如果参数 pattern 描述的字符串没有找到,迭代函数返回nil。
string.match(str,pattern,init)	string.match()只寻找源字串str中的第一个配对. 参数init可选, 指定搜寻过程的起点, 默认为1。
string.sub(s,i,[,j]) 字符串截取 s要截取字符串,i截取开始位置,j截取结束位置。默认-1,最后一个字符
  • 实例
-- 1.string.sub
local str = "hello my name is Tom"
print("原始字符串:",string.format("%q", str))
local sub_1 = string.sub(str,0,5)
print("第一个截取字符串:",string.format("%q", sub_1))
-- 原始字符串:     "hello my name is Tom"
-- 第一个截取字符串:       "hello"

-- 2.string.upper/lower
local str = "Hello Lua"
print(string.upper(str))-- HELLO LUA
print(string.lower(str))-- hello lua

-- 3. string.find
local str = "Hello Lua"
print(string.find(str,"Lua"))--7       9
-- 4. string.reverse
print(string.reverse(str))--auL olleH

-- 5.string格式化
local str1 = "Hello"
local str2 = "Lua"
print(string.format("基本格式化:%s %s",str1,str2))--基本格式化:Hello Lua
-- 日期格式化
date = 2; month=1;year = 2015
print(string.format("日期格式化: %02d/%02d/%02d",date,month,year))-- 02/01/2015
-- 十进制格式化
print(string.format("%.4f", 1/3))-- 0.3333

-- 6.字符串与ASCII相互转换
-- 转换第一个字符
print(string.byte("Lua"))--76
-- 转换第三个字符
print(string.byte("Lua",3))--97
-- 整数ASCII转换为字符
print(string.char(97))--a

-- 7.连接字符串
local str1 = "Hello"
local str2 = "Lua"
print("连接字符串",str1..str2)--连接字符串      HelloLua

-- 8.字符串长度
str = "hello world"
print(string.len(str))--11

-- 9.复制字符串
str = "hello world"
print(string.rep(str,2))-- hello worldhello world

11.3匹配模式

  • Lua中匹配模式直接用常规字符串来描述。
-- %A  表示非字母的字符
print(string.gsub("hello, up-down!", "%A", "."))--hello..up.down. 4
-- 4表示替换几个

12.Lua的数组

  • 数组是相同数据类型元素,按一定顺序排列的集合。可以是一维数组也可以是多维数组。
arr = {"Lua","python","go","c"}
for i=0,4 do
	print(arr[i])
end
--[[
nil
Lua
python
go
c
--]]
  • 正如你所见到的,我们通过整数索引访问数组元素,如果知道索引没有值则返回nil.在Lua索引是以1为开始的。
  • 多维数组
arr = {}
for i=0,4 do
	arr[i] = {}
	for j=1,3 do
		arr[i][j] = i*j
	end
end

for i=0,4 do
	for j=1,3 do
		print(arr[i][j])
	end
end
--[[
0
0
0
1
2
3
2
4
6
3
6
9
4
8
12
--]]

13.迭代器

  • 迭代器是一种对象,它能够用来遍历标准模版库容器中部分或全部元素。每个迭代器对象代表容器中确定的地址。
for k,v in pairs(s) do
	print(k,v)
end
-- k,v 为变量列表。pairs(s)表达式列表
  • 无状态迭代器。类似于ipairs,它会遍历数组每个元素
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
--]]
  • 多种状态迭代器,类似闭包
arr = {"python","go","lua"}

function elementIterator(collection)
	local index = 0
	local count = #collection
	return function()
		index = index + 1
		if index <= count
		then
			return collection[index]
		end
	end
end

for element in elementIterator(arr)
do
	print(element)
end
--[[
python
go
lua
--]]

14.Lua中table表

  • table是Lua的一种数据结构用来帮助我们创建不同数据类型,如:数组,字典等。
  • Lua使用关键型数组,你可以用任意类型的值来做数组的索引,但这个值不能为nil
  • Lua是不固定大小的,你可以根据自己需要进行扩容。
  • Lua是通过table来解决模块,包和对象的.
-- 初始化表
mytable = {}

mytable[1] = "Lua"
-- 移除引用
mytable = nil
-- lua 垃圾回收会释放内存
  • 示例
mytable = {}
mytable[1] = "Lua"
mytable["hello"] = "world"
altertable = mytable
altertable["hello"] = "NONO"
print(mytable["hello"])
-- NONO
  • table操作:
table.concat(table [, sep[,start [,end]]])
--  table.concat()函数列出参数中指定table的数组部分从start位置到end位置的所有元素, 元素间以指定的分隔符(sep)隔开。
table.insert(table,[pos,] value)
-- 在table的数组部分指定位置(pos)插入值为value的一个元素. pos参数可选, 默认为数组部分末尾.
table.maxn(table)
-- 指定table中所有正数key值中最大的key值. 如果不存在key值为正数的元素, 则返回0。
table.remove (table [, pos])
-- 返回table数组部分位于pos位置的元素. 其后的元素会被前移. pos参数可选, 默认为table长度, 即从最后一个元素删起。
table.sort (table [, comp])
-- 对给定的table进行升序排序。
  • 示例
    • 连接:

fruites = {"banana","orange","apple"}
print("连接后字符串:",table.concat(fruites))--连接后字符串:	bananaorangeapple

-- 指定table 连接后字符串
print("连接后字符串",table.concat(fruites,","))--连接后字符串	banana,orange,apple
  • 插入和移除
fruites = {"banana","orange","apple"}

table.insert(fruites,"mango")
print("索引为4 元素:",fruites[4])

-- 索引为2的键处插入
table.insert(fruites,2,"grapes")
print("索引为 2 的元素为 ",fruites[2])



print("最后一个元素为 ",fruites[5])
table.remove(fruites)
print("移除后最后一个元素为 ",fruites[5])

--[[
索引为4 元素:	mango
索引为 2 的元素为 	grapes
最后一个元素为 	mango
移除后最后一个元素为 	nil
--]]

  • 排序
mytable = {"banana","orange","apple","grapes"}
print("排序前")
for k,v in ipairs(mytable) do
	print(k,v)
end

table.sort(mytable)
print("排序后:")
for k,v in ipairs(mytable) do
        print(k,v)
end
--[[
排序前
1	banana
2	orange
3	apple
4	grapes
排序后:
1	apple
2	banana
3	grapes
4	orange
--]]

15.Lua模块

  • 模块类似于封装库,从Lua5.1开始,Lua加入标准模块管理机制。可以把一些公用代码放在一个文件里,以api接口形式在其他地方调用。有利于解耦。

  • module.lua

module = {}
-- 定义公有常量
module.constant = "这是一个常量"

-- 定义公有函数
function module.func1()
	io.write("这是一个公有函数\n")
end


-- 定义私有函数,外部无法访问
local function func2()
	print("这是一个私有函数\n")
end


function module.func3()
    func2()
end

return module


  • test.lua
-- 引入module
require("module")
print(module.constant)-- 这是一个常量
module.func3()-- 这是一个私有函数
  • 加载机制:
对于自定义的模块,模块文件不是放在哪个文件目录都行,函数 require 有它自己的文件路径加载策略,它会尝试从 Lua 文件或 C 程序库中加载模块。

require 用于搜索 Lua 文件的路径是存放在全局变量 package.path 中,当 Lua 启动后,会以环境变量 LUA_PATH 的值来初始这个环境变量。如果没有找到该环境变量,则使用一个编译时定义的默认路径来初始化。

16.Lua中的元素

  • 在Lua table中我们可以访问对应的key来得到value值。但是却无法对两个table进行操作。例如:使用元表我们可以定义Lua如何计算两个table的相加操作a+b。

  • 有两个很重要函数来处理元表

    setmetatable(table,metatable)
    getmetatable(table)
    
  • 示例:

    -- 创建元表
    mytable = setmtetatable({},{})
    getmetatable(mytable)
    

16.1__index 元方法

  • 这是metatable最常用的键、

  • 当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键。如果__index包含一个表格,Lua会在表格中查找相应的键。

    other = { foo = 3 }
    t = setmetatable({}, {__index = other})
    print(t.foo)--3
    print(t.bar)--nil
    

    如果__index包含一个函数的话,Lua就会调用哪个函数,table和键会做为参数传递给函数。__index 元方法查看表中元素是否存在,如果不存在,返回结果为 nil;如果存在则由 __index 返回结果

    mytable = setmetatable({key1 = "value1"},{
    	__index = function (mytable,key)
    		if key == "key2" then
    			return "index生成的value2"
    		else
    			return nil
    		end
    	end
    })
    
    print(mytable.key1)--value1
    print(mytable.key2)--index生成的value2
    --[[
    mytable 表 赋值为 {key1 = "value1"}
    mytable 设置了元表,元方法为__index
    在mytable表中查找 key1,如果找到,返回该元素,找不到则继续。
    在mytable表中查找 key2,如果找到,返回   index生成的value2 ,找不到则继续。
    判断元表有没有__index方法,如果__index方法是一个函数,则调用该函数。
    元方法中查看是否传入 "key2" 键的参数(mytable.key2已设置),如果传入 "key2" 参数返回 "index生成的value2",否则返回 mytable 对应的键值。
    --]]
    
    

    简洁版本

    mytable = setmetatable({key1 = "value1"}, { __index = { key2 = "index生成的value2" } })
    print(mytable.key1,mytable.key2)
    
  • 总结

    查找顺序:
    	1.在表中查找,如果找到,返回元素,找不到继续。
    	2.判断该表是否有元表,如果没有元表,返回nil.有元表则继续
    	3.判断元表有没有 __index 方法,如果 __index 方法为 nil,则返回 nil;如果 __index 方法是一个表,则重复 1、2、3;如果 __index 方法是一个函数,则返回该函数的返回值。
    

16.2 __newindex 元方法

  • __newindex元方法用来对表更新。而__index则用来对表访问。当你给表的一个缺少的索引赋值,解释器就会查找__newindex 元方法:如果存在则调用这个函数而不进行赋值操作。

    以下实例演示了 __newindex 元方法的应用:

  • 示例

    mymetatable = {}
    mytable = setmetatable({key1="value1"},{__newindex=mymetatable})
    print(mytable.key1)-- value1
    
    mytable.newkey = "new value2"
    print(mytable.newkey,mymetatable.newkey)-- nil	new value2
    
    mytable.key1 = "new value1"
    print(mytable.key1,mymetatable.key1)-- new value1	nil
    

    以上实例中表设置了元方法__newindex,对新索引键(newkey)赋值时,(mytable.newkey="new value2") 会调用元方法,而不进行赋值。而如果对已经存在索引键。则会进行赋值,而不会调用元方法__newindex

    mytable = setmetatable({key1 = "value1"},{
    	__newindex = function(mytable,key,value)
    		rawset(mytable, key, "\""..value.."\"")
    	end
    })
    
    mytable.key1 = "new value1"
    mytable.key2 = "new value2"
    
    print(mytable.key1,mytable.key2)-- new value1	"new value2
    
    

16.3 为表添加操作符

  • 示例

    -- 自定义函数,用于计算表中元素个数
    function table_maxn(t)
    	local mn = 0
    	for k,v in pairs(t) do
    		if mn < k then
    			mn = k
    		end
    	end
    	return mn
    end
    
    
    -- 两表相加操作
    
    mytable = setmetatable({1,2,3},{
    	__add = function(mytable,newtable)
    		for i=1, table_maxn(newtable) do
    			table.insert(mytable,table_maxn(mytable)+1,newtable[i])
    
    		end
    		return mytable
    	end
    })
    
    
    newtable = {4,5,6}
    
    mytable = mytable + newtable
    for _,v in ipairs(mytable) do
    	print(v)
    end
    --[[
    1
    2
    3
    4
    5
    6
    --]]
    
  • 前置双下划线方法还有很多如下:

    __add		对应的运算符 '+'
    __sub	对应的运算符 '-'
    __mul	对应的运算符 '*'
    __div	对应的运算符 '/'
    __mod	对应的运算符 '%'
    __unm	对应的运算符 '-'
    __concat	对应的运算符 '..'
    __eq	对应的运算符 '=='
    __lt	对应的运算符 '<'
    __le	对应的运算符 '<='
    

16.4 __call 元方法

  • __call元方法在Lua调用一个值时侯同时被调用。

    
    mytable = setmetatable({1,2,3},{
    	__call = function(mytable,newtable)
    		sum = 0
    		for i=1,table_maxn(mytable) do
    			sum = sum + mytable[i]
    		end
    		for i=1, table_maxn(newtable) do
    			sum = sum + newtable[i]
    		end
    		return sum
    	end
    })
    newtable = {10,20,30}
    print(mytable(newtable)) -- 66
    

16.5 __tostring 元方法

  • __tostring元方法用于修改表的输出行为:

    mytable = setmetatable({1,2,3},{
    	__tostring = function(mytable,newtable)
    		sum = 0
    		for i=1,table_maxn(mytable) do
    			sum = sum + mytable[i]
    		end
    		return "表中所有元素和为 " .. sum
    	end
    })
    
    print(mytable) -- 表中所有元素和为 6
    

17.协同程序

  • Lua协同程序与线程比较类似:拥有独立堆栈,独立的局部变量。独立的指令指针。同时又与其它协同程序共享全局变量和其它大部分东西。

  • 线程与协同程序区别

    线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。
    在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。
    
    协同程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同。
    
  • 语法

    coroutine.create()	创建 coroutine,返回 coroutine, 参数是一个函数,当和 resume 配合使用的时候就唤醒函数调用
    coroutine.resume()	重启 coroutine,和 create 配合使用
    coroutine.yield()	挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合使用能有很多有用的效果
    coroutine.status()	查看 coroutine 的状态
    注:coroutine 的状态有三种:dead,suspended,running,具体什么时候有这样的状态请参考下面的程序
    coroutine.wrap()	创建 coroutine,返回一个函数,一旦你调用这个函数,就进入 coroutine,和 create 功能重复
    coroutine.running()	返回正在跑的 coroutine,一个 coroutine 就是一个线程,当使用running的时候,就是返回一个 corouting 的线程号
    
  • 示例

    co = coroutine.create(
    	function(i)
    		print(i);
    	end
    )
    
    coroutine.resume(co,1)
    print(coroutine.status(co))
    
    print("------------------")
    
    co = coroutine.wrap(
    	function(i)
    		print(i)
    	end
    )
    
    co(i)
    
    print("------------------")
    
    co2 = coroutine.create(
        function()
            for i=1,10 do
                print(i)
                if i == 3 then
                    print(coroutine.status(co2))  --running
                    print(coroutine.running()) --thread:XXXXXX
                end
                coroutine.yield()
            end
        end
    )
    
    coroutine.resume(co2) --1
    coroutine.resume(co2) --2
    coroutine.resume(co2) --3
    
    print(coroutine.status(co2))   -- suspended
    print(coroutine.running())
    
    print("----------")
    

18.错误处理

  • 我们可以使用两个函数:assert 和error来处理,示例如下

    local function add(a,b)
    	assert (type(a) == "number", "a不是一个数字")
    	assert (type(b) == "number", "b不是一个数字")
    	return a + b
    end
    add(10)
    --[[
    lua: demo1.lua:634: b不是一个数字
    stack traceback:
    	[C]: in function 'assert'
    	demo1.lua:634: in function 'add'
    	demo1.lua:638: in main chunk
    	[C]: ?
    --]]
    
  • error 函数

    • 终止正在执行函数,并返回message的内容做为错误信息。
    • Level参数指示获得错误位置:
    Level=1[默认]:为调用error位置(文件+行号)
    Level=2:指出哪个调用error的函数的函数
    Level=0:不添加错误位置信息
    
  • pcall 和 xpcall、debug

    • Lua中处理错误,可以使用函数pcall来包装需要执行代码
    if pcall(function_name, ….) then
    -- 没有错误
    else
    -- 一些错误
    end
    
  • 示例

    res = pcall(function(i) print(i) error('error..') end, 33)
    print(res)
    -- false
    
    function myfunc ()
    	n = n/nil
    end
    function myerrfunc(err)
    	print("ERROR:",err)
    end
    status = xpcall(myfunc,myerrfunc)
    print(status)
    
    -- ERROR:	demo1.lua:646: attempt to perform arithmetic on global 'n' (a nil value)
    -- false
    

19.Lua垃圾回收

  • Lua 采用了自动内存管理。 这意味着你不用操心新创建的对象需要的内存如何分配出来, 也不用考虑在对象不再被使用后怎样释放它们所占用的内存。
  • Lua 运行了一个垃圾收集器来收集所有死对象 (即在 Lua 中不可能再访问到的对象)来完成自动内存管理的工作。 Lua 中所有用到的内存,如:字符串、表、用户数据、函数、线程、 内部结构等,都服从自动管理。
  • Lua实现增量标记-扫描收集器:垃圾收集器间歇率和垃圾收集器步进倍率(这两个数字都使用百分数为单位)。
垃圾收集器间歇率控制着收集器需要在开启新的循环前要等待多久。 增大这个值会减少收集器的积极性。 当这个值比 100 小的时候,收集器在开启新的循环前不会有等待。 设置这个值为 200 就会让收集器等到总内存使用量达到 之前的两倍时才开始新的循环。

垃圾收集器步进倍率控制着收集器运作速度相对于内存分配速度的倍率。 增大这个值不仅会让收集器更加积极,还会增加每个增量步骤的长度。 不要把这个值设得小于 100 , 那样的话收集器就工作的太慢了以至于永远都干不完一个循环。 默认值是 200 ,这表示收集器以内存分配的"两倍"速工作。
  • 垃圾回收函数
Lua 提供了以下函数collectgarbage ([opt [, arg]])用来控制自动内存管理:

collectgarbage("collect"): 做一次完整的垃圾收集循环。通过参数 opt 它提供了一组不同的功能:

collectgarbage("count"): 以 K 字节数为单位返回 Lua 使用的总内存数。 这个值有小数部分,所以只需要乘上 1024 就能得到 Lua 使用的准确字节数(除非溢出)。

collectgarbage("restart"): 重启垃圾收集器的自动运行。

collectgarbage("setpause"): 将 arg 设为收集器的 间歇率。 返回 间歇率 的前一个值。

collectgarbage("setstepmul"): 返回 步进倍率 的前一个值。

collectgarbage("step"): 单步运行垃圾收集器。 步长"大小"由 arg 控制。 传入 0 时,收集器步进(不可分割的)一步。 传入非 0 值, 收集器收集相当于 Lua 分配这些多(K 字节)内存的工作。 如果收集器结束一个循环将返回 true 。

collectgarbage("stop"): 停止垃圾收集器的运行。 在调用重启前,收集器只会因显式的调用运行。
posted @ 2020-08-15 22:29  是阿凯啊  阅读(113)  评论(0编辑  收藏  举报