快速入门 Lua 语言的基本语法
Lua是动态类型语言,变量不需要类型定义。
数据类型
数据类型 | 描述 |
---|---|
nil | 空(在条件表达式中相当于false) |
Boolean | 布尔值:true / false |
number | 浮点数(Lua中整数浮点数不做区分) |
string | 字符串(Lua中字符字符串通用string) |
function | 由C或Lua编写的函数 |
userdata | 表示任意存储在变量中的C数据结构 |
thread | 表示执行的独立线程,用于执行协同程序 |
table | 表,关联数组,数组的索引可以是数字,字符串或表类型,在Lua中,table的创建是通过“构建表达式”来完成,最简单构造表达式是{},用来创建一个空表。 |
userdata 跟C语言挂钩。
thread 相当于Unity中的携程。
print("Hello World")
输出,末尾不用添加;
,添加了也是不会错的。
给变量赋不同类型
-- 当前a的类型为number
a = 10;
-- 重新赋值a的类型为string
a = "小明"
算数运算符
下列列出Lua语言中的常用的算术运算符,假设A的值为10,B的值为20:
操作符 | 描述 | 实例 |
---|---|---|
+ | 加法 | A+B输出结果30(若是加号两边不能转换成number类型则无法相加) |
- | 减法 | A-B输出结果-10 |
* | 乘法 | A*B输出结果200 |
/ | 除法 | B/A输出结果2 |
% | 取余 | B%A输出结果0 |
^ | 乘幂 | A^2输出结果100 |
- | 负号 | -A输出结果-10 |
关系运算符
下列为Lua语言中的常用的关系运算符,设定A的值为10,B的值为20:
操作符 | 描述 | 实例 |
---|---|---|
== | 等于,检测两个值是否相等,相等返回true,否则返回false | (A==B)为false |
~= | 不等于,检测两个值是否相等,不相等返回true,否则返回false | (A~=B)为true |
> | 大于,如果左边的值大于右边的值,返回true,否则返回false | (A>B)为false |
< | 小于,如果右边的值大于左边的值,返回true,否则返回false | (A<B)为true |
>= | 大于等于,如果左边的值大于等于右边的值,返回true,否则返回false | (A>=B)为false |
<= | 小于等于,如果左边的值小于等于右边的值,返回true,否则返回false | (A<=B)为true |
逻辑运算符
下列为Lua语言中的常用逻辑运算符,设定A的值为true,B的值为false
操作符 | 描述 | 实例 |
---|---|---|
and | and两边条件都为true,则返回true,否则返回false | (A and B)为false |
or | or两边条件都为false,则返回false,否则返回true | (A or B)为true |
not | 如果条件为true,逻辑非为false | not(A and B)为true |
if...else语句
if
和elseif
后面一定要加关键字then
a = 100
if a > 90 then
print("A")
elseif a > 80 then
print("B")
else
print("C")
end
注意:Lua中0为true,C#中0为false。
循环
while循环
a = 0
while a < 10 do
print(a)
a = a + 1
end
数值for循环
for i = 1, 10, 1 do
print("Hello World")
end
repeat...until
和C#中的do...while()类似,但do...while()是条件不符合跳出,repeat..until是符合条件跳出。
a = 0
repeat
print(a);
a = a + 1
until a > 10
C#和Lua用法区别
语言风格 | OOP面向对象型语言 | OP面向过程 function函数式编程 |
---|---|---|
强语言 | 弱语言 | |
基本数据类型 | 整数、浮点数、布尔、字符、字符串 | number数字、booleam布尔、string字符串 |
空类型 | null | nil |
定义类型 |
int a = 10; 声明变量时需要定义类型 |
a = 10 不需要定义类型 |
全局变量 |
static bool a = true; 类型前需要添加static 关键词 |
a = 10 就是全局变量,local a = 10 添加local 就变成局部变量 |
数据交换 | 数据交换时需要定义中间量临时存储 |
a,b = 10,20 a,b = b,a 不需要定义中间量 |
运算符 + | 数据相加,字符串连接 | 代表数字运算(加号左右两边必须是number类型或者可以转换成number类型,否则就会报错) |
运算符 .. | 没有 | 用于字符串的连接 |
运算符^ | Math.power(基数,指数) |
2^2 |
运算符+=、-=、*=、/=、%=
|
有 | 没有 |
运算符不等于 | != |
~= |
逻辑运算符 | `&&、 | |
运算符# | 没有 | 求字符串或表的长度(所占内存长度) |
控制流程 | `if...else if...else... | if...then elseif...then else end |
循环 | for、do while、while |
for、while、repeat..until |
函数方法 | 访问修饰符 返回值 方法名(参数定义) | function 方法名(参数定义) 方法体 end |
Lua方法类型
-- 没有返回值没有参数
function Do1()
end
-- 有参数没有返回值(因为Lua不需要定义数据类型,故可以传任何数值)
function Do2(a,b)
end
-- 有参数有返回值
function Do3(a,b)
return a+b;
end
-- 多返回值
function Do4(a,b)
return a+b, a-b, a*b, a/b
end
-- 可以使用多个参数进行承接
local a,b,c,d =Do4(1,2)
Lua方法传递
使用方法一:
function Do(a, b)
return a + b
end
-- 方法也是可以传递
t = Do
print(t(2, 3))
使用方法二:
function Do(f)
if f~=nil then
f();
end
end
-- 方法作为参数进行传递(匿名方法)
Do(function ()
print("lll")
end)
可变参数
三个点表示可变参数
function Do(...)
-- 使用局部变量接住可变参数
local args = {...}
-- select 传入可变参数的数量
print(select("#",...))
-- 从第二位开始输出后面的数值
print(select(2,...))
for key, value in pairs(args) do
print(value);
end
end
-- 方法执行
Do(1,3,5)
table 表
table是lua的一种数据结构,用来帮助我们创建不同的数据类型,如:数组,字典等。
可以使用任意的数值做数组的索引,但是不能为nil。
大小不是固定的,根据自己的需要进行扩容。
mytable = {}
创建一个空表
pairs
批量输出所有的数据(包含数组和字典)
ipairs
只能遍历连续的数组结构部分,若数组第七位数据是没有数据的,那么遍历到第六位就会停止。
table数组长度动态扩容
table表中数组数据扩容是以2的倍数进行的。
若当前数组的容量是4的话,若向第5个位置添加元素数据,但若是前四个位置是有空位,便不会进行扩容,而是作为键值对进行存储,若是前四个位置都是有数据的,没有空位,数组将会扩容,数据将存储到数组的第五个格子的位置。
-- 初始化表中数据
local mytable = {"zhang_san", "li_si", "wang_wu",teacher = "xiao_zhao"}
-- 访问数组数据
print(mytable[1])
-- 访问键值对
print(mytable["teacher"])
-- 访问键值对
print(mytable.teacher)
-- 数组添加
mytable[4] = "youyou"
-- 添加键值对
mytable.adivser = "kong_sha_sha"
-- 表中数据删除
mytable.teacher = nil
-- 获得数组长度(连续数组)
print(#mytable)
-- 遍历表中所有的数据(数组顺序输出,键值对无无序输出)
for key, value in pairs(mytable) do
print(key..value);
end
-- 遍历数组结构部分
for index, value in ipairs(mytable) do
print(value)
end
使用表来承接方法的多返回值
function Do(a, b)
return a+b,a-b,a*b,a/b
end
-- 多返回值可以使用表来承接
local args = {Do(1, 2)}
for key, value in pairs(args) do
print(key,value)
end
table的索引是从1开始的。
表中数据插入
local t = {"ping_guo", "xiang_jiao"}
-- 向表t中添加字符串 "ju_zi"
table.insert(t, "ju_zi")
-- 插入到表中指定位置,当前位置的元素向后移
table.insert(t, 1, "ming_meng")
表中指定数据删除
local t = {"ping_guo", "xiang_jiao"}
-- 移除表中最后一个元素
table.remove(t)
-- 根据索引删除表中数据
table.remove(t,1)
Lua模块
模块类类似一个封装库
定义一个mylib.lua脚本
-- 定义一个mylib的模块
mylib = {}
-- 这是模块中的一个变量
mylib.name = "llll"
-- 返回当前模块
return mylib
引用模块
-- 引入mylib模块,和C#中使用using类似
require("mylib")
-- 使用mylib中定义的数据
print(mylib.name)
:. self三者的区别
t = {money = 10000}
-- 静态方法
function t.Hua_Qian(t)
t.money = t.money -100
end
-- 成员方法
function t:Hua_Qian()
self.money = self.money -100
end
-- 静态方法调用
t.Hua_Qian(t)
-- 成员方法调用
t:Hua_Qian()
print(t.money)
.相当于静态方法,可以多个表共同使用一个
:相当于成员方法,只供本表进行使用
self和this相当,相当于是当前表
:使用频率较多。
闭包
当方法执行完毕后方法内存的变量没有销毁,就形成了闭包。
如:通过for循环动态创建点击按钮,并且在在创建的时候给按钮添加的事件或着数据,并不会随着方法执行完毕而销毁。
使用闭包实现ipairs迭代器
local t = {1,2,3,4}
local function mpairs()
local index = 0
return function ()
index = index + 1
return t[index]
end
end
for value in mpairs() do
print(value)
end
元表
元表是允许针对当前表的行为进行修改,具体改什么依赖元表中的元方法
通过表实现两个vector3相加
v = {x = 1,y = 2,z = 3}
p = {x = 4,y = 5,z = 6}
-- 给其中一个表添加元表(两个表相加,改变其中一个表即可)
setmetatable(v,{
__add = function (a,b)
local q = {}
q.x = a.x + b.x
q.y = a.y + b.y
q.z = a.z + b.z
return q
end
})
local g = v + p
print(g.x,g.y,g.z)
__index 最常用的元方法
若果是方法的话,先找原始表中是否有这个键,元方法有这个键就返回这个键对应的值,这个键不存在就找对应的元方法__index,如果元方法是一个方法,调用这个方法,返回这个方法的返回值,如果不是方法是一个表的话,返回另一个表中去查。
local t = {name = "gg"}
local v = {age = 10}
setmetatable(t,{
__index = v
})
print(t.age)
数学库
Math数学库
- abs 求绝对值
- modf 劈分一个小数,整数部分 小数部分
- ceil 向上取整
- floor 向下取整
数学库追加
数学库中没有四舍五入的函数,我们可以自己添加一个对应的函数。
-- 给math添加四舍五入的函数
function math.round(num)
-- 使用数学库的拆分,对传入的数据进行拆分
local a,b = math.modf(num)
if b >= 0.5 then
return a + 1
else
return a
end
end
字符串
- byte 是用来把字符串转换成
ascii
数字(中文字符转换成字节是不对的) - char 返回数字对应的字符
- sub 字符串截取(英文对应的是一个字节,中文对应的是三个字节)
- find 字符串查找
- gsub 字符串替换
字符串依次输出每个字符
local function stringPair(str)
local index = 1
return function ()
-- 判断index是否大于字节长度
if index > #str then
return nil
end
-- 截取索引为index的字符
local temp = string.sub( str, index, index)
-- 判断当前截取的字符是否大于128(大于等于128表示是汉字,要三个字符才能组成一个字符)
if string.byte(temp) >= 128 then
-- 截取index到index+2三个字符
local res = string.sub(str,index,index + 2)
index = index + 3
return res
else
-- 截取一个字符
local res = string.sub(str,index,index)
index = index + 1
return res
end
end
end
local function showPairs(str)
for value in stringPair(str) do
print(value)
end
end
showPairs("好久好久1212")
Lua中方法和表示引用传递,其他的都是值传递。
推荐阅读
-
纯干货分享 | 研发效能提升——敏捷需求篇-而敏捷需求是提升效能的方式中不可或缺的模块之一。 云智慧的敏捷教练——Iris Xu近期在公司做了一场分享,主题为「敏捷需求挖掘和组织方法,交付更高业务价值的产品」。Iris具有丰富的团队敏捷转型实施经验,完成了企业多个团队从传统模式到敏捷转型的落地和实施,积淀了很多的经验。 这次分享主要包含以下2个部分: 第一部分是用户影响地图 第二部分是事件驱动的业务分析Event driven business analysis(以下简称EDBA) 用户影响地图,是一种从业务目标到产品需求映射的需求挖掘和组织的方法。 在软件开发过程中可能会遇到一些问题,比如大家使用不同的业务语言、技术语言,造成角色间的沟通阻碍,还会导致一些问题,比如需求误解、需求传递错误等;这会直接导致产品的功能需求和要实现的业务目标不是映射关系。 但在交付期间,研发人员必须要将这些需求实现交付,他们实则并不清楚这些功能需求产生的原因是什么、要解决客户的哪些痛点。研发人员往往只是拿到了解决方案,需要把它实现,但没有和业务侧一起去思考解决方案是否正确,能否真正的帮助客户解决问题。而用户影响地图通常是能够连接业务目标和产品功能的一种手段。 我们在每次迭代里加入的假设,也就是功能需求。首先把它先实现,再逐步去验证我们每一个小目标是否已经实现,再看下一个目标要是什么。那影响地图就是在这个过程中帮我们不断地去梳理目标和功能之间的关系。 我们在软件开发中可能存在的一些问题 针对这些问题,我们如何避免?先简单介绍做敏捷转型的常规思路: 先做团队级的敏捷,首先把产品、开发、测试人员,还有一些更后端的人员比如交互运维的同学放在一起,组成一个特训团队做交付。这个团队要包含交付过程中所涉及的所有角色。 接着业务敏捷要打通整个业务环节和研发侧的一个交付。上图中可以看到在敏捷中需求是分层管理的,第一层是业务需求,在这个层级是以用户目标和业务目标作为输入进行规划,同时需要去考虑客户的诉求。业务人员通过获取到的业务需求,进一步的和团队一起将其分解为产品需求。所以业务需求其实是我们真正去发布和运营的单元,它可以被独立发布到我们的生产环境上。我们的产品需求其实就是产品的具体功能,它是我们集成和测试的对象,也就是我们最终去部署到系统上的一个基本单元。产品需求再到了我们的开发团队,映射到迭代计划会上要把它分解为相应的技术任务,包括我们平时所说的比如一些前端的开发、后端的开发、测试都是相应的技术任务。所以业务敏捷要达到的目标是需要去持续顺畅高质量的交付业务价值。 将这几个点串起来,形成金字塔结构。最上层我们会把业务目标放在整个金字塔的塔尖。这个业务目标是通过用户的目标以及北极星指标确立的。确认业务目标后再去梳理相应的业务流程,最后生产。另外产品需求包含了操作流程和业务规则,具需求交付时间、工程时间以及我们的一些质量标准的要求。 谈到用户影响的地图,在敏捷江湖上其实有一个传说,大家都有一个说法叫做敏捷需求的“任督二脉”。用户影响地图其实就是任脉,在黑客马拉松上用过的用户故事地图其实叫督脉。所以说用户影响地图是在用户故事地图之前,先帮我们去梳理出我们要做哪些东西。当我们真正识别出我们要实现的业务活动之后,用户故事地图才去梳理我们整个的业务工作流,以及每个工作流节点下所要包含的具体功能和用户故事。所以说用户影响地图需要解决的问题,我们包括以下这些: 首先是范围蔓延,我们在整张地图上,功能和对应的业务目标是要去有一个映射的。这就避免了一些在我们比如有很多干系人参与的会议上,那大家都有不同想法些立场,会提出很多需求(正确以及错误的需求)。这个时候我们会依据目标去看这些需求是否真的是会影响我们的目标。 这里提到的错误需求,比如是利益相关的人提出的、客户认为产品应该有的、某个产品经理需求分析师认为可以有的....但是这些功能在用户影响地图中匹配不到对应目标的话,就需要降低优先级或弃掉。另外,通常我们去制定解决方案的时候,会考虑较完美的实现,导致解决方案括很多的功能。这个时候关键目标至关重要,会帮助我们梳理筛选、确定优先级。 看一下用户影响到地图概貌 总共分为一个三层的结构: 第一层why,你的业务目标哪个是最重要的,为什么?涉及到的角色有哪些? 第二层how ,怎样产生影响?影响用户角色什么样的行为? (不需要去列出所有的影响,基于业务目标) 第三层what,最关键的是在梳理需求时不需一次把所有细节想全,这通常团队中经常遇到的问题。 我们用这个例子来看一下 这是一个客服中心的影响地图,业务目标是 3个月内不增加客服人数的前提下能支持1.5倍的用户数。此业务目标设定是符合 smart 原则的,specific非常的具体,miserable 是可以衡量的,action reoriented是面向活动的, real list 也是很实际的。 量化的目标会指引我们接下来的行动,梳理一个业务目标,尽量去量化,比如 :我们通过打造一条什么样的流水线,能够提高整个部署的效率,时间是原来的 1/2 。这样才是一个能量化的有意义的目标。 回到这幅图, how 层级识别出来的内容,客服角色:想要对它施加的影响,把客户引导到论坛上,帮助客户更容易的跟踪问题,更快速的去定位问题。初级用户:方论坛上找到问题。高级用户:在论坛上回答问题。通过我们这些用户角色,进行活动,完成在不增加客户客服人数的前提下支持更多的用户数量。 最后一个层级,才是我们日常接触比较多的真正的功能的特性和需求,比如引导到客户到论坛上,其实这个产品就需要有一个常见问题的论坛的链接。这个层次需要我们团队进一步地在交付,在每个迭代之前做进一步的梳理,细化成相应的用户故事。 这个是云智慧团队中,自己做的影响地图的范例,可以看下整个的层级结构。序号表示优先级。 那我们用户影响地图可以总结为:
-
GO 语言入门指南:基本语法和常用功能说明(数据类型) | YTCA
-
华为 HarmnyOS TypeScript 基本语法快速入门
-
快速了解Logback的基本概念与入门指南
-
快速掌握Web开发:从手动使用web框架理解其核心理念,到WSGI、ERF模块与动静态页面,Jinja2模板语法应用,揭秘Python三大主流web框架——Django的安装入门与基础三步走
-
快速入门vite的基本设置教程
-
从入门到精通:Ognl 编程语言的基础语法指南
-
从入门到精通:Ognl 编程语言的基础语法指南
-
快速入门 Lua 语言的基本语法
-
入门级指南:IDE如何支持Solidity编程语言的语法特性