Lua基础

  1. lua中声明的变量默认是全局变量
  2. 局部变量声明:变量名前加上local
  3. 没有被声明的变量都是nil(相对于java语言的null)
  4. 字符串的连接符是..(相对于java语言的+)
  5. 获取字符串长度:#变量名,1个汉字占3个字符长度,1个英文占1个字符长度

1.类型之间的转换:

  • 数字转字符串:tostring()
  • 字符串转数字:tonumber()

转换失败值为nil

2.函数

声明:
function 函数名(...)
   ...函数体 
end

函数名 = function(...)
   ...函数体 
end

function可以当作参数传递,允许匿名定义。

函数的构造式:function(param) end

变长参数
function fun(...)
    -- ...就是变长参数,需要用一个表存起来再用
    arg = {...}
    print(arg[1])
end
函数嵌套
function F1()
    return function()
        print("123")
    end
end
注意:
  • Lua中函数不支持重载
  • Lua是解释型语言,是从上到下执行,不能在函数未定义之前使用函数

3.数组:

数字下标声明方式:
变量名 = {1,"abc",{},function()  end}

注意:下标从1开始(java从0开始)

字符串下标声明方式:
变量名 = {
    字符串a = 1,
    字符串b = "1234",
    字符串c = function()
        
        end,
    字符串d = 123456
}
print(变量名["字符串a"])
print(变量名.字符串a)
操作:
  • 插入操作:table.insert(变量名,(可选)位置,值)
  • 移除操作:table.remove(变量名,位置)

4.全局表(global)

说明:全局表是lua里一个特殊的table叫做_G,这个表存储了所有的全局变量。

本地变量不会存入大_G表中。

5.布尔值

  • 真为true
  • 假为false

Lua认为false和nil为假,true和非nil为真(包括0)。要于c语言做区分

6.运算符

算术运算符
操作符 描述 实例
+ 加法 A + B 输出结果 30
- 减法 A - B 输出结果 -10
* 乘法 A * B 输出结果 200
/ 除法 B / A 输出结果 2
% 取余 B % A 输出结果 0
^ 乘幂 A^2 输出结果 100
- 负号 -A 输出结果 -10
// 整除运算符(>=lua5.3) 5//2 输出结果 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。

注意:lua中不等于为~=,java中不等于为!=

逻辑运算符
操作符 描述 实例
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。

注意:Lua中不支持三目运算符,但是可以使用and和or来模拟三目运算符(x>y) and x or y

其他运算符
操作符 描述 实例
连接两个字符串 a…b ,其中 a 为 "Hello " , b 为 “World”, 输出结果为 “Hello World”。
# 一元运算符,返回字符串或表的长度。 #“Hello” 返回 5
运算符优先级

从高到低的顺序:

^
not    - (unary)
*      /       %
+      -
..
<      >      <=     >=     ~=     ==
and
or

7.流程控制:

--[ 0 为 true ]
if(0)
then
    print("0 为 true")
end

lua中使用 then … end表示一个代码块

8.循环:

Lua 语言提供了以下几种循环处理方式:

循环类型 描述
while 循环 在条件为 true 时,让程序重复地执行某些语句。执行语句前会先检查条件是否为 true。
for 循环 重复执行指定语句,重复次数可在 for 语句中控制。
repeat…until 重复执行循环,直到 指定的条件为真时为止
循环嵌套 可以在循环内嵌套一个或多个循环语句(while do … end;for … do … end;repeat … until;)
while 循环:

判断条件为 true 时会重复执行循环体语句。

while(condition)
do
   statements
end
for 循环:

for 循环语句可以重复执行指定语句,重复次数可在 for 语句中控制。

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

  • 数值for循环
  • 泛型for循环(相当于java中的foreach )
数值for循环:
for var=exp1,exp2,exp3 do  
    <执行体>  
end 

var 从 exp1 变化到 exp2,每次变化以 exp3 为步长递增 var,并执行一次 “执行体”。exp3 是可选的,如果不指定,默认为1。

泛型for循环:
--打印数组a的所有值  
a = {"one", "two", "three"}
for i, v in ipairs(a) do
    print(i, v)
end 

i是数组索引值,v是对应索引的数组元素值。ipairs是Lua提供的一个迭代器函数,用来迭代数组。

实例:

days = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}  
for i,v in ipairs(days) do  print(v) end 
repeat…until 循环:

repeat…until 循环语句不同于 for 和 while循环,for 和 while 循环的条件语句在当前循环执行开始时判断,而 repeat…until 循环的条件语句在当前循环结束后判断。(相当于java中的do while循环)

repeat
   statements
until( condition )

9.常用函数

取整函数

数学库中提供了三个取整函数:floor、ceil和modf。

  • floor:向负无穷取整

  • ceil:向正无穷取整

  • modf:向零取整

  • dep:弧度转角度

  • abs:绝对值

  • cos、sin:三角函数

  • max:最大值

  • min:最小值

  • modf:把整数和小数分离,返回两个参数

  • random:随机数

    • 先设置随机数种子:randomseed(tostring(os.time()):reverse():sub(1,7))
  • pow:幂运算

  • sqrt:开方

时间:

  • os.date(“*t”):获取当前时间表
  • os.time():获取当前时间戳

10.元表和元表方法

元表的概念
  • 任何表变量都可以作为另一个表变量的元表
  • 任何表变量都可以有自己的元表
  • 当我们子表(有元表的表)中进行一些特定操作时,会执行元表的内容

Lua 提供了元表(Metatable),允许我们改变 table 的行为,每个行为关联了对应的元方法。

设置元表
  • setmetatable(table,metatable): 对指定 table 设置元表(metatable),如果元表(metatable)中存在 __metatable 键值,setmetatable 会失败。
  • getmetatable(table): 返回对象的元表(metatable)。
mytable = {}                          -- 普通表
mymetatable = {}                      -- 元表
setmetatable(mytable,mymetatable)     -- 把 mymetatable 设为 mytable 的元表

以上代码也可以直接写成一行:

mytable = setmetatable({},{})

以下为返回对象元表:

getmetatable(mytable)                 -- 这会返回 mymetatable
__index 元方法

这是 metatable 最常用的键。

概念:当子表中 找不到某一个属性时,会到元表中的 __index指定的表去找索引

我们可以在使用 lua 命令进入交互模式查看:

meta = {
	age = 17,
	__tostring = function(t) 
		return "我的名字是" .. t.name 
	end,
	__call = function( mytable,canshu1 )
		print(mytable.name)
		print(canshu1)
	end,
	-- __len = function(mytable)
	-- 	return #mytable.name
	-- end
}
meta.__index = meta
mytable = {
	name = "qimeile"
}
setmetatable(mytable,meta)
print(mytable.age)

如果__index包含一个函数的话,Lua就会调用那个函数,table和键会作为参数传递给函数。

__index 元方法查看表中元素是否存在,如果不存在,返回结果为 nil;如果存在则由 __index 返回结果。

实例
mytable = setmetatable({key1 = "value1"}, {
 __index = function(mytable, key)
  if key == "key2" then
   return "metatablevalue"
  else
   return nil
  end
 end
})

print(mytable.key1,mytable.key2)

实例输出结果为:

value1    metatablevalue

实例解析:

  • mytable 表赋值为 {key1 = “value1”}

  • mytable 设置了元表,元方法为 __index。

  • 在mytable表中查找 key1,如果找到,返回该元素,找不到则继续。

  • 在mytable表中查找 key2,如果找到,返回 metatablevalue,找不到则继续。

  • 判断元表有没有__index方法,如果__index方法是一个函数,则调用该函数。

  • 元方法中查看是否传入 “key2” 键的参数(mytable.key2已设置),如果传入 “key2” 参数返回 “metatablevalue”,否则返回 mytable 对应的键值。

我们可以将以上代码简单写成:

mytable = setmetatable({key1 = “value1”}, { __index = { key2 = “metatablevalue” } })
print(mytable.key1,mytable.key2)

总结

Lua 查找一个表元素时的规则,其实就是如下 3 个步骤:

  • 1.在表中查找,如果找到,返回该元素,找不到则继续
  • 2.判断该表是否有元表,如果没有元表,返回 nil,有元表则继续。
  • 3.判断元表有没有 __index 方法,如果 __index 方法为 nil,则返回 nil;如果 __index 方法是一个表,则重复 1、2、3;如果 __index 方法是一个函数,则返回该函数的返回值。
  • 使用rawget(表名,属性名)函数:只会在自己身上查找这个属性变量,不会继续查找元表。

__newindex 元方法

__newindex 元方法用来对表更新,__index则用来对表访问 。

当赋值时,如果赋值一个不存在的索引,那么会把这个值赋值到newindex所指的表中,不会修改自己

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

实例
mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })

print(mytable.key1)

mytable.newkey = "新值2"
print(mytable.newkey,mymetatable.newkey)

mytable.key1 = "新值1"
print(mytable.key1,mymetatable.key1)

以上实例执行输出结果为:

value1
nil    新值2
新值1    nil

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

以下实例使用了 rawset 函数来更新表:

实例

mytable = setmetatable({key1 = “value1”}, {
__newindex = function(mytable, key, value)
rawset(mytable, key, “"”…value…“"”)
end
})

mytable.key1 = “new value”
mytable.key2 = 4

print(mytable.key1,mytable.key2)

以上实例执行输出结果为:

new value    "4"

总结:

  • 使用rawset(表名, 属性名, 值)函数:修改自身,不会修改元表中__newindex索引指向的表。

为表添加操作符

以下实例演示了两表相加操作:

实例

– 计算表中最大值,table.maxn在Lua5.2以上版本中已无法使用
– 自定义计算表中最大键值函数 table_maxn,即返回表最大键值
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
})

secondtable = {4,5,6}

mytable = mytable + secondtable
for k,v in ipairs(mytable) do
print(k,v)
end

以上实例执行输出结果为:

1    1
2    2
3    3
4    4
5    5
6    6

__add 键包含在元表中,并进行相加操作。 表中对应的操作列表如下:(注意:是两个下划线)

模式 描述
__add 加,对应的运算符 ‘+’.
__sub 减,对应的运算符 ‘-’.
__mul 乘,对应的运算符 ‘*’.
__div 除,对应的运算符 ‘/’.
__mod 取余,对应的运算符 ‘%’.
__unm 取负,对应的运算符 ‘-’.
__pow 幂,对应的运算符 ‘^’.
__concat 拼接,对应的运算符 ‘…’.
__eq 等于,对应的运算符 ‘==’.
__lt 小于,对应的运算符 ‘<’.
__le 小于等于,对应的运算符 ‘<=’.
__idiv 向下取整除法,对应的运算符 ‘//’.
__len 取长度,对应的运算符 ‘#’.

注意:如果要用条件运算符比较两个对象,这两个对象的元表一定要一致,才能准确调用方法


__call 元方法
概念:
  • 当子表被当作一个函数来使用时 会默认调用这个元表章__call中的内容
  • 当希望传参数时,一定要记住 默认的第一个参数 是调用者自己(子表自己作为了第一个参数)

__call 元方法在 Lua 调用一个值时调用。以下实例演示了计算表中元素的和:

实例
meta = {
	__tostring = function(t) 
		return "我的名字是" .. t.name 
	end,
	__call = function( mytable,canshu1 )
		print(mytable.name)
		print(canshu1)
	end
}
mytable = {
	name = "qimeile"
}
setmetatable(mytable,meta)
mytable(12)

以上实例执行输出结果为:

qimeile
12

__tostring 元方法

__tostring 元方法用于修改表的输出行为。以下实例我们自定义了表的输出内容:

实例
mytable = setmetatable({ 10, 20, 30 }, {
    __tostring = function(mytable)
        sum = 0
        for k, v in pairs(mytable) do
             sum = sum + v
         end
        return "表所有元素的和为 " .. sum
    end
})
print(mytable)

以上实例执行输出结果为:

表所有元素的和为 60
meta = {
	__tostring = function(t) 
		return "我的名字是" .. t.name 
	end }
mytable = {
	name = "qimeile"
}
setmetatable(mytable,meta)
print(mytable)

以上实例执行输出结果为:

我的名字是qimeile

11.闭包

  • lua语言中的函数是第一类值。意味着Lua语言中的函数于其他常见类型的值(如数值和字符串)具有同等权限:一个程序可以将某个函数保存到变量中(全局变量和局部变量均可)或表中,也可以将某个函数作为参数传递给其他函数,还可以将某个函数做为其他函数的返回值返回。
  • 从技术上讲,Lua语言中只有闭包而没有函数,函数本身只是闭包的一种原型。不过尽管如此,只要不会引起混淆,就仍将使用术语“函数”来指代闭包。

12.表 table

表是一切复杂数据的基础:数组、二维数组、字典、类等等

数组和二维数组:
  • 索引从1开始
  • 中间为nil会断掉长度获取不准确
  • #:长度获取
  • 自定义索引,计算长度时从1开始,忽略小于等于0的索引
字典:
  • 字典存储的是键值对(Key和Value)
  • 如果要是模拟的字典 遍历要使用pairs
类:
  • Lua中模式是没有面向对象的,需要我们自己实现
-- 将表当作一个类来使用
Student = {
	name = "qimeile",
	sex = "男",
	age = 25,
    //内部定义类的函数
	speak = function()
        -- 想要在表内部函数中 调用表本身的属性或者方法
		--一定要指定是谁的 所以要使用 表名.属性 或 表名.方法
        print("你好!我叫" .. Student.name) 
    end
}
//外部定义类的函数
function Student:Up()
	print(self.name)
end
表的公共方法:
  • insert:插入

  • remove:默认移除表中最后一个索引的内容,第二个参数可以指定移除的索引

  • sort:排序,默认升序排序,第二个参数可以传入排序规则

    t1 = {3,1,6,4,5}
    -- 降序规则
    table.sort(t1,function(a,b)
    	if(a>b) then
    		return true
    	end
    end)
    
  • concat:拼接,用于拼接表中的string和number元素,返回值是string

13. 多脚本

加载脚本

关键字:require(“脚本路径”)

  • 如果是require加载执行的脚本,再次require加载则不会被执行

  • Package.loaded[“脚本名”]:通过返回值,判断脚本是否被执行

卸载脚本
  • Package.loaded[“脚本名”] = nil:脚本卸载

14. 特殊用法

  • 支持多变量赋值
  • 支持多返回值

15. 协同程序

协程的创建:

  • coroutine.create():(常用方式)协程的本质是一个线程对象
    • 运行方式:coroutine.resume()
  • coroutine.wrap():返回的协程是一个函数类型
    • 运行方式:和函数调用方式相同
  • coroutine.yield(返回值):协程的挂起,可以有返回值
    • coroutine.resume()执行的默认有一个boolean类型的返回值表示协程是否执行成功,用户自定义的返回值从第二个开始
    • coroutine.wrap()方式创建的则没有默认的boolean类型返回值,用户自定义的返回值从第一个开始
  • coroutine.status(协程对象):协程的状态
    • dead:结束
    • suspended:暂停
    • running:进行中
  • coroutine.running():返回协程编号

16. 面向对象

面向对象的三大特性:封装、继承、多态

封装:
print("***********封装**********")

Object = {}
Object.id = math.random(0,12)
function Object:toString()
	print(self.id)
end
function Object:new()
	local obj = {}
	self.__index = self
	setmetatable(obj,self)
	return obj
end

local a = Object:new()

print("a:" .. a.id)
继承:

实现方法:利用_G来根据字符串创建一个新的表(类),元表和__index相关知识点

print("***********继承**********")

function Object:extends(className)
	_G[className] = {}
	local obj = _G[className]
	self.__index = self
	-- 子类调用父类的方法
	obj.base = self
	setmetatable(obj,self)
end

a:extends("a2")
print("a2:" .. a2.id)
多态:

概念:相同方法名 子类有不同的处理逻辑。

实现方法:直接重写这个方法

如果保留父类逻辑:加入自定义 base属性,extends方法中赋值

print("***********多态**********")
Object:extends("GameObject")
GameObject.posX = 0
GameObject.posY = 0
function GameObject:Move()
	self.posX = self.posX + 1
	self.posY =self.posY + 1
	print(self.posX)
	print(self.posY)
end
GameObject:extends("Player")
function Player:Move()
    -- 不要使用self.base:Move()
	self.base.Move(self)
end
local p1 = Player:new()
p1:Move()
p1:Move()
local p2 = Player:new()
p2:Move()

**注意:**通过base调用父类方法时,一定记住不要用冒号,通过.然后自己传入第一个参数 进入父类内部

17.垃圾回收

  • Lua中有自动定时进行垃圾回收的方法,但是在Unity热更新开发中,尽量不要去用自动垃圾回收,性能有损耗
  • collectgarbage(“collect”):手动释放垃圾

你可能感兴趣的:(Lua,lua)