Lua语法学习整理

单行注释:--
多行注释:--[[ 
注释内容
 ]]

Lua教程 | 菜鸟教程
【唐老狮】Unity热更新之Lua语法


1.变量

1.1 作用域

  • 全局变量: 没添加关键字 无论再哪里声明的都是全局变量(全局变量会被存放再_G表中)

  • 局部变量:加入关键字local的就是本地变量(出来循环、函数、脚本和协程后会被销毁)


1.2 使用

  • 声明时 不需要声明变量类型 会自动判断类型 (类似C#的var)
  • 变量可以随便赋值,会自动识别类型
  • 使用type函数可以得到当前变量的存储数据的类型,函数返回值是string类型
  • 使用没声明的变量不会报错,默认值是nil

1.3 简单变量类型

  • nil: 表示无效值
    • 给变量赋值为nil,也有解除占用、删除的作用,会被资源回收
  • number :表示双精度类型的实浮点数(C#中的int float double 都属于number)
  • string : 字符串(lua不分char 和 string)
    • 字符串长度获取关键字#
    • 多行字符串的定义 1.插入转义字符\n 2.[[…]] 双中括号内可以接收回车进行换行输入
    • 字符串拼接关键字.. ,也可以使用格式化函数 string.format("%d",num)(类似C语言)
    • 其他类型转字符串 tostring()
  • boolean : 布尔值(true、false) 只有 false 和 nil 看作是 false,其他的都为 true

1.4 复杂变量类型

1.4.1 function(函数)

  • 定义

    • function 函数名() ...... end
    • 函数名 = function() ...... end
  • 使用

    • 如果传入的参数或返回值个数不匹配,多了丢弃,少了补nil
    • 支持多返回值 在函数调用前面声明多个变量接取即可
    • 支持可变长参数 关键字是...。(原理是把参数当作表,在函数内使用前最好定义表提取出来)
    • 不支持函数重载,先声明的函数会被后声明的函数覆盖
    • 函数嵌套:在函数的返回值里面返回一个匿名函数,利用函数也是变量的特性,这样可以改变传入参数的生命周期
    --闭包 改变传入参数的生命周期
    function F9(x)
    	return function(y)
    		return x+y
    	end
    end
    
    f10 = F9(10)		--f10 = function(x) return x + 10 end
    print(f10(5))		--输出15 因为 f10(5) = function(5) return 5 + 10 end
    

1.4.2 table(表)

Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字或者是字符串。

  • 使用
    • 表支持自定义索引,默认索引从1开始,使用自定义索引如果和默认索引冲突,自定义索引的变量会被默认的覆盖
    • #是获取表长度的关键字
      • 表的长度取决于表内元素的索引,会从1开始往后数,如果自定义索引不在范围内则不会被计算在长度内
      • 表中的nil会影响表的长度,遇到连续两个nil会认为表已经结束
  • 表内函数
    • 表内声明 变量名 = function() ...... end
    • 表外声明
      • 表名.函数名 = function() ...... end (没有默认传参)
      • 表名:函数名 = function() ...... end (默认传参 是第一个 参数就是调用的表,多态的关键,使用self关键字表示)
    • 公共方法
    • 插入 table.insert(表名1,表名2)
    • 删除指定元素 table.remove(表名1,下标) 表名一:目标表 下标:是移除内容的索引(默认移除最后一个)
    • 排序 table.sort(表名,function(x,y) ...... end ) 参数一:目标表 参数二: 排序规则函数 (默认排序)
    • 拼接 table.concat(表一,拼接字符串,下标一,下标二) 参数一:目标表 , 参数二: 拼接时连接处添加的字符串 , 参数三:是目标表的开始下标 , 参数四 是目标表拼接的结束下标

1.4.3 userdata(自定义类型)

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


1.4.4 thread(线程)

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

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

  • 协程的本质是一个线程类型的变量

    创建函数 coroutine.create(函数) coroutine.wrap()
    返回值类型 返回一个类型为线程的协程变量 返回一个类型为函数的协程变量
    使用 coroutine.resume() 直接调用函数
    使用函数返回值 默认第一个返回值是协程是否启动成功,第二个是挂起函数的返回值 没用协程是否成功启动的返回值
    • 挂起函数 coroutine.yield(返回值) yield里面填协程的返回值
--协程状态查看:
coroutine.running(协程对象)		--返回正在运行的协程的线程号
coroutine.status(协程对象)      --返回协程对象的状态
--[[
dead:结束状态 代表协程全部执行完
suspended: 暂停状态 协程被挂起
running: 进行中  在协程中才会出现
]]

2.运算符

2.1 算数运算符

没有
+-*/%^(幂运算)` ++--(自增自减) , +=-=(复合运算符)

2.2 关系运算符

<, >, >=, <=, ==, ~=(不等于)


2.3 逻辑运算符

有 且:and , 或:or 否:not
lua中保留了“短路”概念 : 例如 在做逻辑判断and的时候 如果前面条件为false 则后面条件不判断了,or同理


2.4 其他运算符

.. : 字符串连接
# : 返回字符串或表的长度
lua中不支持位运算和三目运算符
但可以利用逻辑运算符的特性来模拟三目运算符

例如: (条件) and 结果1 or 结果2 相当于 (条件) ? 结果1 : 结果2
因为如果 条件为真 则直接为结果一 true and 结果1 … 后面会被省略 直接输出结果一
而如果条件为假 则 (条件) and 结果1 or 结果2 = >false or 结果2 直接输出结果二


3.条件分支语句

单分支 多分支
if 条件 then ...... end if 条件 then ...... else ...... end
- if 条件 then ...... elseif 条件2 then ...... end

4.循环语句

调用 特点
while while 条件 do … end 该条件是进入条件
repeat repeat … until 条件 该条件是结束条件
for for 变量名 = 初始值, 结束值 , 步进 do … end 步进可不填 默认是1
ipairs(迭代器) for 变量名1,变量名2 in ipairs(表名) do … end 原理是通过#获取表长度进行变量(获取表长度会被影响不准确)。变量一是表变量的索引,变量二是表变量的值
pairs(迭代器) for 变量名1,变量名2 in pairs(表名) do … end pairs可以变量表的全部键值对 , 顺序是先默认下标(1到n) 再到自定义索引

5.元表

Lua 提供了元表(Metatable),允许我们改变 table 的行为,每个行为关联了对应的元方法。
任何表变量都可以作为另一表变量的元表 ,任何表变量都可以有自己的元表

--元表函数
setmetatable(table,metatable) --对指定table设置元表(meatatblen) 如果元表(metatable)中存在 __metatablen 键值,setmetatable会失败
getmetatable(table) --返回对象的元表(metatable)
特定操作 使用场景 注意事项
__tostring 当子表要被当作字符串使用时,会默认调用元表中的__tostring方法 子表调用元表的__tostring方法时 会默认把自己当作第一个参数传入
__call 当子表要被当作函数使用时,会默认调用元表中的__call方法 子表调用元表的__call方法时 会默认把自己当作第一个参数传入,传参是从第二个开始
__index 当子表中找不到某一个属性时,会到元表中指定的__index表去找。如果元表也没有,回到元表的元表找 __index表的指定 最好写在表外面,写在表内可能会被跳过
rawget() 使用这个函数,只会去找自己身上的变量不会去找元表的__index
__newIndex 当对表内元素赋值时,如果赋值一个不存在的索引,则会把这个值赋到元表中指定的__newIndex表中
rawset() 使用这个函数,只会对自身表的属性赋值,不会去找元表的__newIndex
运算符重载 当子表使用某一运算符时,会调用对应重载方法 +, -, *, /, %, ^, ==, <, <=, .. 没有小于和小于等于,只能用大于,大于等于

6.特性

6.1 脚本执行(模块与包)

可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。

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

6.1.1脚本调用

require("脚本路径") (如果和当前文件同层级 就是脚本名本身)

  • 效果上和函数调用类似,也可以添加返回值,但只能有一个返回值
  • 加载执行过,未被卸载就不会再被执行

6.1.2脚本卸载

package.loaded["路径名"] 返回值是boolean 脚本是否被执行

package.load["路径名"] 赋值为nil或false 即可卸载脚本

6.2 面向对象(模仿)

  • 封装(利用函数的冒号传参和元表可以把常用方法封装到方法表中)
Object = {
    
    }		--所有对象的基类(元表)

--	封装  把新建表方法封装到Object中
function Object:new()
	local obj = {
    
    }
	--给新实例化出来的对象 设置元表(相当于根据模板属性和方法实例化对象)
	self.__index = self
	setmetatable(obj,self)
	return obj
end
  • 继承(利用元表来实现 表到表之间的继承关系)
--	继承  利用元表实现表之间的继承
function Object:subClass(className)
	--根据名字和父类(Object) 生成一张表 相当于根据父类生成子类
	_G[className] = {
    
    }
	local obj = _G[className]
	obj.base = self 	--把自身元表(父类)保存起来
	self.__index = self
	setmetatable(obj,self)
end
  • 多态(在表的继承中使用变量base存储父类表本身,再根据传参即可实现 相同的方法 不同的执行逻辑)
--	根据父类声明新的类
Object:subClass("GameObject")

--	成员变量
GameObject.posX = 0
GameObject.posY = 0

--	成员方法
function GameObject:Move()
	self.posX = self.posX + 1
	self.posY = self.posY + 1
end

--	实例化对象使用
local obj = GameObject:new()
print(obj.posX)			--GameObject.posX
obj:Move()				--定义了obj.posX 并赋值为 GameObject.posX+1
print(obj.posX)

local obj2 = GameObject:new()
print(obj2.posX)		--GameObject.posX
obj2:Move()				--定义了obj2.posX 并赋值为 GameObject.posX+1
print(obj2.posX)

--	声明了一个新的类 Player 继承 GameObject
GameObject:subClass("Player")
Player.posX = 60	
Player.posY = 60

--	多态 重写了 GameObject的Move方法
function Player:Move()
	--	base调用父类方法 用.传自己作为第一个参数 而不是固定使用base(因为自己没有base的话会使用父类的base)
	self.base.Move(self)
end

print("---------------多态实例化---------------")
local p1 = Player:new()
print(p1.posX)				--Player.posX
p1:Move()					--p1.posX 并赋值为 Player.posX+1
print(p1.posX)

local p2 = Player:new()
print(p2.posX)				--Player.posX
p2:Move()					--p2.posX 并赋值为 Player.posX+1
print(p2.posX)

6.3 垃圾回收

关键字: collectgarbage 解除占用(不会用到对象)的变量会被回收

  • collectgarbage("collect"): 做一次完整的垃圾收集循环
  • collectgarbage("count"): 以 K 字节数为单位返回 Lua 使用的总内存数。 这个值有小数部分,所以只需要乘上 1024 就能得到 Lua 使用的准确字节数(除非溢出)。
  • collectgarbage("restart"): 重启垃圾收集器的自动运行。
  • collectgarbage("setpause"): 将 arg 设为收集器的 间歇率。 返回 间歇率 的前一个值。
  • collectgarbage("setstepmul"): 返回 步进倍率 的前一个值。
  • collectgarbage("step"): 单步运行垃圾收集器。 步长"大小"由 arg 控制。 传入 0 时,收集器步进(不可分割的)一步。 传入非 0 值, 收集器收集相当于 Lua 分配这些多(K 字节)内存的工作。 如果收集器结束一个循环将返回 true 。
  • collectgarbage("stop"): 停止垃圾收集器的运行。 在调用重启前,收集器只会因显式的调用运行。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/anxious333/article/details/132076762