五邑隐侠,本名关健昌,12年游戏生涯。 本教程以 Unity 3D + VS Code + C# + tolua 为例。

如果你还没有编程基础,建议你先学习一些编程基础。本文不是完全菜鸟教程,主要针对有其他语言经验的开发者,如果想看菜鸟教程,建议看菜鸟教程的 Lua教程

先看一个简单类的代码

  1 ---@class BsnsPack @Base class of business pack
2 local BsnsPack = {
3 -- class fields
4 maxSerialNo = 0,
5 }
6
7 BsnsPack.__index = BsnsPack
8
9 --- new()
10 ---@return BsnsPack
11 function BsnsPack:new()
12 local o = {}
13
14 -- member fields
15 o.serialNo = 0
16 o.mod = 0
17 o.cmd = 0
18 o.payload = nil
19
20 -- bind BsnsPack methods
21 setmetatable(o, self)
22 return o
23 end
24
25 --- set serial No.
26 ---@param serialNo number
27 function BsnsPack:setSerialNo(serialNo)
28 self.serialNo = serialNo
29 end
30
31 --- get serial No.
32 ---@return number
33 function BsnsPack:getSerialNo()
34 return self.serialNo
35 end
36
37 --- set mod
38 ---@param mod number
39 function BsnsPack:setMod(mod)
40 self.mod = mod
41 end
42
43 --- get mod
44 ---@return number
45 function BsnsPack:getMod()
46 return self.mod
47 end
48
49 --- set cmd
50 ---@param cmd number
51 function BsnsPack:setCmd(cmd)
52 self.cmd = cmd
53 end
54
55 --- get cmd
56 ---@return number
57 function BsnsPack:getCmd()
58 return self.cmd
59 end
60
61 --- set payload
62 ---@param payload any
63 function BsnsPack:setPayload(payload)
64 self.payload = payload
65 end
66
67 --- get payload
68 ---@return any
69 function BsnsPack:getPayload()
70 return self.payload
71 end
72
73 function BsnsPack.test()
74 print(BsnsPack.serialNo)
75 end
76
77 --- testPrivate
78 ---@param self BsnsPack
79 local function testPrivate(self)
80 print(self.serialNo)
81 end
82
83 ---@alias Request BsnsPack @Request is BsnsPack
84 local Request = BsnsPack
85
86 ---@class Response : BsnsPack @Response class
87 local Response = {}
88 setmetatable(Response, BsnsPack) -- bind super methods
89 Response.__index = Response
90
91 --- new()
92 ---@return Response
93 function Response:new()
94 local o = BsnsPack:new()
95
96 -- member fields
97 o.code = 0
98
99 setmetatable(o, nil) -- remove original metatable
100 setmetatable(o, self) -- bind Response methods
101 return o
102 end
103
104 --- get result code
105 ---@return number
106 function Response:getCode()
107 return self.code
108 end
109
110 local bsnsPack = {}
111 bsnsPack.BsnsPack = BsnsPack
112 bsnsPack.Request = Request
113 bsnsPack.Response = Response
114
115 return bsnsPack

1、第1行:这是一行注释

Lua的行注释以两个减号 -- 开头,

class注解:---@class TYPE[: PARENT_TYPE {, PARENT_TYPE}]  [@comment]

这样有利于 VS Code 代码提示,例如将鼠标放到代码中出现 BsnsPack 的地方上,会有小弹窗提示这个table的key,以及key的类型。

用得比较多的注解有 ---@class,---@return,---@param

2、第2行,定义一个叫 BsnsPack 的class(通过table模拟)。

Lua里没有类,Lua的结构化数据类型叫table,基于key-value结构。相对于其他语言的 map / dictionary。访问一个table的key对应的值,可以用点 . 来访问,也可以用中括号[]来访问

Lua里没有单独的数组结构,也是基于table,数组下标是key,数组元素是value,要注意的是,Lua里数组下标是从1开始的。

创建table的最简单方式就是花括号 {},创建一个空table。

Lua是脚本语言,变量不需要指定类型,只需要给它赋值。所以 BsnsPack = {maxSerialNo = 0,} 相当于定义了个变量 BsnsPack,它的值是一个table。

Lua的变量默认是全局的,加载到内存的Lua代码都可以访问这个变量。为了避免命名冲突和意外修改,一般建议变量定义为局部变量,限制它的作用域。在变量前面加个 local定义局部变量。

这里定义的 BsnsPack ,作用域只在这个文件里。其他文件不能访问。也可以在函数、代码块里用 local 定义局部变量。

3、第7行,给 BsnsPack一个叫 __index 的 key 赋值为 BsnsPack 自己

Lua 的 table 里,__index 是个特殊的key,这是 Lua实现类和继承的关键。
Lua里有个概念叫做元表。Lua定义了一些语言默认key,这些key一般跟 +、-、*、/等操作符、key的访问、值更新关联,这些key叫做元方法(Lua里的函数/方法也可以作为值),这些元方法合起来叫元表。

Lua里设置元表的方法是代码第 21 行的 function setmetatable(t, metatable),调用这个方法会让参数 metatable 成为 参数 t 的元表。

设置元表后,在代码里访问参数 t 的一个key时会发生以下情况:

1)Lua先在 t 里找,看有没有这个key,如果有,就返回这个key的值。否则,执行2)

2)Lua看参数 metatable 有没有 __index 这个key,如果有,就在 __index 对应的值里查找(__index的值如果是表,在这个表里查找;如果是函数,执行这个函数)

BsnsPack.__index = BsnsPack,如果其他的table设置 BsnsPack 为元表,就可以访问 BsnsPack 所有的key。 这些key的值如果是方法,就可以调用这些方法。
所以 BsnsPack 可以定义方法的模板,这就跟class类似。BsnsPack定义的数据key,相当于静态字段class field。BsnsPack定义的方法key,可以是成员方法member method,也可以是class method,后面介绍
 

4、第11~23行,定义BsnsPack的一个叫new的key,它的值是一个方法

Lua里一个代码块不用花括号{},通过end作为结束标记。

定义方法用 function 开头,用点.或者冒号:分割talbe名和方法名,

用冒号:定义的方法,会有个默认参数self,相当于调用者,如果外部用 BsnsPack:new() 这样调用,则self == BsnsPack,如果用a:new()这样调用,self==a。

用点.定义的方法,没有默认参数,只能显式写参数self。

一般地,用冒号:定义构造对象的方法(例如第11行的 function BsnsPack:new()),以及成员方法member method(例如第23行的 function BsnsPack:setSerialNo(serialNo) )

1)当在其他地方调用 BsnsPack:new()时,方法BsnsPack:new()的定义里的self是 BsnsPack,setmetatable(o, self)相当于设置对象 o 的类为 BsnsPack

2)调用 o:setSerialNo(serialNo) 时,这里的self是对象o,只改对象o的serialNo,其他对象的serialNo不受影响。

用点.定义静态方法class method(例如第69行的 function BsnsPack.test() )

1)在其他地方通过 BsnsPack.test()调用

建议,方法定义的时候是冒号:,调用的时候用冒号:,定义的时候是点.,调用的时候也用点.

构造方法不一定叫new,只是为了统一,建议都用new,与其他语言一致。

方法new里面的 local o = {},定义的key都是成员字段member field(每次调用方法 BsnsPack:new() 都创建一个新的 table并对其字段初始化后返回)

Lua没有私有的成员方法,可以定义文件的 local 方法,把对象作为参数self显式的传进去(例如第79行 local function testPrivate(self))

5、第84行,给类BsnsPack定义一个别名 Request,其实就是把一个table赋值给另外一个变量

6、第87~102行,定义一个类Response,继承基类BsnsPack

第87行,定义子类Response

第88行,设置元表,使得Response可以访问BsnsPack所有的key(继承BsnsPack所有的方法)

第89行,所有对象可以访问Response所有的key(通过递归,包括BsnsPack所有的key)

第94行,通过调用BsnsPack构造方法初始化o,o是BsnsPack的对象,拥有基类所有的member field

第97行,定义Response相对于基类新增的字段code

第99、100行,修改o的元表为Response,这样o可以访问Response所有的成员方法 member method(通过递归,包括BsnsPack所有的成员方法)

Response可以重写BsnsPack的方法

1 function Response:getPayload()
2 return self.payload
3 end

由于Lua里访问key,先在table本身查找,如果没有才在元表查找,所以会调用重写的方法,实现多态。

7、第110~115行,导出本文件定义的类。

由于class的定义都是以 local 方式定义的局部变量,外部不能访问,所以要把它当作文件的返回值 return

如果该文件只导出一个class,直接return这个局部变量就可以,(例如,如果只导出BsnsPack,return BsnsPack 就可以)

由于本文件需要导出3个class,这里把他们放到一个table里导出

其他文件需要访问这个文件的class,需要调用require方法导入进来,该方法的参数是路径(不含后缀.lua),返回值是这个lua文件的return值

1 local bsnsPack = require("Assets.Lua.bsns.bsns_pack")
2 local Request = bsnsPack.Request
3 local Response = bsnsPack.Response

8、如果想模块化管理,把一个模块所有的类通过一个文件暴露给其他模块,可以在这个文件定义一个局部变量,把这个模块所有的文件的类,都通过require导入进来,并赋值给跟类同名的key,最后返回这个局部变量

文件bsns.lua

 1 local bsns = {}
2
3 local bsnsPack = require("Assets.Lua.bsns.bsns_pack")
4 bsns.Request = bsnsPack.Request
5 bsns.Response = bsnsPack.Response
6
7 bsns.BsnsMod = require("Assets.Lua.bsns.bsns_mod")
8 bsns.BsnsCenter = require("Assets.Lua.bsns.bsns_center")
9
10 return bsns

5、简单语法介绍

1)Lua里的语句不需要分号;结尾

2)Lua常用的基本数据类型有nil、boolean、number、string、function、table

3)获取数组长度用 #数组变量,例如

1 local array = {"Lua", "Tutorial"}
2 local len = #array
3 print(len)

4)遍历数组用

1 for i, v in ipairs(table) do
2
3 end

5)遍历对象用

1 for k, v in pairs(obj) do
2
3 end

6)其他语法请查阅菜鸟教程

6、Lua代码规范可参考 https://lua.ren/topic/172/

Unity3D开发入门教程(二)—— Lua入门的更多相关文章

  1. 无废话ExtJs 入门教程二十一[继承:Extend]

    无废话ExtJs 入门教程二十一[继承:Extend] extjs技术交流,欢迎加群(201926085) 在开发中,我们在使用视图组件时,经常要设置宽度,高度,标题等属性.而这些属性可以通过“继承” ...

  2. 无废话ExtJs 入门教程二十[数据交互:AJAX]

    无废话ExtJs 入门教程二十[数据交互:AJAX] extjs技术交流,欢迎加群(521711109) 1.代码如下: 1 <!DOCTYPE html PUBLIC "-//W3C ...

  3. SpringBoot入门教程(二)CentOS部署SpringBoot项目从0到1

    在之前的博文<详解intellij idea搭建SpringBoot>介绍了idea搭建SpringBoot的详细过程, 并在<CentOS安装Tomcat>中介绍了Tomca ...

  4. PySide——Python图形化界面入门教程(二)

    PySide——Python图形化界面入门教程(二) ——交互Widget和布局容器 ——Interactive Widgets and Layout Containers 翻译自:http://py ...

  5. 无废话ExtJs 入门教程二[Hello World]

    无废话ExtJs 入门教程二[Hello World] extjs技术交流,欢迎加群(201926085) 我们在学校里学习任何一门语言都是从"Hello World"开始,这里我 ...

  6. mongodb入门教程二

    title: mongodb入门教程二 date: 2016-04-07 10:33:02 tags: --- 上一篇文章说了mongodb最基本的东西,这边博文就在深入一点,说一下mongo的一些高 ...

  7. Elasticsearch入门教程(二):Elasticsearch核心概念

    原文:Elasticsearch入门教程(二):Elasticsearch核心概念 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:ht ...

  8. RabbitMQ入门教程(二):简介和基本概念

    原文:RabbitMQ入门教程(二):简介和基本概念 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn ...

  9. JasperReports入门教程(二):中文打印

    JasperReports入门教程(二):中文打印 背景 在上一篇中我们介绍了JasperReport的基本入门,也展示了一个报表.但是我们的示例都是使用的英文,如果我们把需要打印的数据改为中文会怎么 ...

  10. C#微信公众号开发系列教程二(新手接入指南)

    http://www.cnblogs.com/zskbll/p/4093954.html 此系列前面已经更新了两篇博文了,都是微信开发的前期准备工作,现在切入正题,本篇讲解新手接入的步骤与方法,大神可 ...

随机推荐

  1. 渐进式web应用 (PWA)

    PWA(渐进式 Web 应用)运用现代的 Web API 以及传统的渐进式增强策略来创建跨平台 Web 应用程序. PWA的特点: Discoverable, 内容可以通过搜索引擎发现. Instal ...

  2. window安装ab压力测试

    ab是Apache HTTP server benchmarking tool的缩写,可以用以测试HTTP请求的服务器性能,也是业界比较流行和简单易用的一种压力测试工具包 ## 下载 下载地址:(ht ...

  3. 【Python】CV2的一些基本操作

    ·导入: import cv2 ·读取图片: img = cv2.imread('路径') 使用函数cv2.imread(filepath,flags)读入一副图片 filepath:要读入图片的完整 ...

  4. DevOps的分与合

    一.抽象的 DevOps DevOps 是使软件开发和 IT 团队之间的流程自动化的一组实践,以便他们可以更快,更可靠地构建,测试和发布软件.DevOps 的概念建立在建立团队之间协作文化的基础上,这 ...

  5. SpringMVC 入门、请求、响应

    目录 SpringMVC 概述 SSM 简介 MVC 简介 SpringMVC 简介 入门案例 Spring 技术架构 SpringMVC 基础配置 常规配置 Controller 加载控制 静态资源 ...

  6. logging模块学习

    logging模块: https://docs.python.org/3/howto/logging.html#logging-basic-tutorial 本记录教程 日志记录是一种跟踪某些软件运行 ...

  7. AcWing1264. 动态求连续区间和 (线段树做法)

    1.题目 给定 n 个数组成的一个数列,规定有两种操作,一是修改某个元素,二是求子数列 [a,b] 的连续和. 输入格式 第一行包含两个整数 n 和 m,分别表示数的个数和操作次数. 第二行包含 n ...

  8. qt5读取所有本机IP

    说明 需要添加 network模块 本文介绍的函数将读取所有本机IP,包括 ipv4和ipv6 本文演示版本 qt5.14 头文件 #include <QHostAddress> #inc ...

  9. 【LeetCode】1161. Maximum Level Sum of a Binary Tree 解题报告 (C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 BFS 日期 题目地址:https://leetcod ...

  10. 【LeetCode】67. Add Binary 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 BigInteger类 模拟加法 日期 题目地址:h ...