Lua 学习笔记之一
前言
本文针对的读者是有经验的C/C++程序员,希望了解Lua或者迅速抓住Lua的关键概念和模式进行开发的。因此本文并不打算教给读者条件语句的语法或者函数定义的方式等等显而易见的东西,以及一些诸如变量、函数等编程语言的基本概念。本文只打算告诉读者Lua那些与C/C++显著不同的东西以及它们实际上带来了怎样不同于C/C++的思考方式。不要小看它们,它们即将颠覆你传统的C/C++的世界观!
本文一共分初阶、进阶和高阶三大部分,每个部分又有若干章节。读者应当从头至尾循序渐进的阅读,但是标有"*"号的章节(主要讨论OO在Lua中的实现方式)可以略去而不影响对后面内容的理解。读者只要把前两部分完成就可以胜任Lua开发的绝大部分任务。高阶部分可作为选择。
初阶话题
八种基本类型
基本类型 | 描述 | 备注 |
---|---|---|
数值(number) | 内部以double表示 | |
字符串(string) | 总是以零结尾,但可以包含任意字符(包括零),因此并不等价于C字符串, 而是其超集 | |
布尔(boolean) | 只有"true"或者"false"两个值。 | |
函数(function) | Lua的关键概念之一。不简单等同于C的函数或函数指针。 | |
表(table) | 异构的Hash表。Lua的关键概念之一。 | |
userdata | 用户(非脚本用户)定义的C数据结构。脚本用户只能使用它,不能定义。 | |
线程(thread) | Lua协作线程(coroutine),与一般操作系统的抢占式线程不一样。 | |
nil | 代表什么也没有,可以与C的NULL作类比,但它不是空指针。 |
函数
实例代码
lua
function foo(a, b, c, ...)
local sum = a + b
return sum, c --函数可以返回多个值
end
r1, r2 = foo(1, "123", "hello") --平行赋值 print(r1,r2);
输出结果
lua
124hello
函数基本使用方法
-
函数定义
用关键字function定义函数,以关键字end结束
-
局部变量
用关键字local定义。如果没有用local定义,即使在函数内部定义的变量也是全局变量
-
函数可以返回多个值
return a, b, c, ...
-
平行赋值
a,b = c, d
-
全局变量
前面的代码定义了三个全局变量:foo、r1和r2
表
实例代码
lua
local a = {}
local b = {x = 1,["hello,"] = "world!"}
a["astring"] = "ni,hao!"
a[1] = 100
a["a table"] = b
for k,v in pairs(a) do
print(k,"=>",v);
end
输出结果
lua
1=>100
astring=>ni,hao!
atable=>table: 0xfd59570
表使用方法
-
定义表(Table)的方式
a={}, b = {...}
-
访问表的成员
通过
.
或者[]
运算符来访问表的成员。注意:表达式a.b等价于
a[b]
,但不等价于a[b]
-
表项的键和值
任何类型的变量,除了
nil
,都可以做为表项的键。从简单的数值、字符串到复杂的函数、表等等都可以;同样,任何类型的变量,除了nil,都可以作为表项的值。给一个表项的值赋nil意味着从表中删除这一项,比如令a.b= nil
,则把表a
中键为b
的项删除。如果访问一个不存在的表项,其值也是nil,比如有c = a.b
,但表a
中没有键为b
的项,则c等于nil
。
一种简单的对象实现方式
实现代码
lua
function create(name,id)
local obj = {name = name,id = id}
function obj:SetName(name)
self.name = name
end
function obj:GetName()
return self.name
end
function obj:SetId(id)
self.id = id
end
function obj:GetId()
return self.id
end
return obj
end
local myCreate = create("sam",001)
for k,v in pairs(myCreate) do
print(k,"=>",v)
end
print("myCreate's name:",myCreate:GetName(),"myCreate's id:",myCreate.GetId(myCreate))
myCreate:SetId(100)
myCreate:SetName("Hello Kity")
print("myCreate's name:",myCreate:GetName(),"myCreate's id:",myCreate:GetId())
输出结果
lua
SetName=>function: 0x85efc50
GetId=>function: 0x85efc10
id=>1
SetId=>function: 0x85efd00
GetName=>function: 0x85efce0
name=>sam
myCreate's name:sammyCreate's id:1
myCreate's name:Hello KitymyCreate's id:100
对象实现描述
-
对象工厂模式
如前面代码的create函数
-
用表来表示对象
把对象的数据和方法都放在一张表内,虽然没有隐藏私有成员,但对于简单脚本来说完全可以接受。
-
成员方法的定义
function obj:method(a1, a2, ...) ... end 等价于function obj.method(self, a1, a2, ...) ... end 等价于obj.method = function (self, a1, a2, ...) ... end
-
成员方法的调用
obj:method(a1, a2, ...) 等价于obj.method(obj, a1, a2, ...)
简单继承
实现代码
lua
local function CreateRobot(name, id)
local obj = {name = name, id = id}
function obj:SetName(name)
self.name = name
end
function obj:GetName()
return self.name
end
function obj:SetId(id)
self.id = id
end
function obj:GetId()
return self.id
end
return obj
end
local function createFootballRobot(name, id, position)
local obj = CreateRobot(name, id)
obj.position = "right back"
function obj:SetPosition(p)
self.position = p
end
function obj:GetPosition()
return self.position
end
return obj
end
local mycreateFootballRobot = createFootballRobot("Tom", 1000, "广州")
print(
"mycreateFootballRobot's name:",
mycreateFootballRobot:GetName(),
"myCreate's id:",
mycreateFootballRobot:GetId(),
mycreateFootballRobot:GetPosition()
)
mycreateFootballRobot:SetName("麦迪")
mycreateFootballRobot:SetId(2000)
mycreateFootballRobot:SetPosition("北京")
print(
"mycreateFootballRobot's name:",
mycreateFootballRobot:GetName(),
"myCreate's id:",
mycreateFootballRobot:GetId(),
mycreateFootballRobot:GetPosition()
)
输出结果
lua
mycreateFootballRobot's name:TommyCreate's id:1000right back
mycreateFootballRobot's name:麦迪myCreate's id:2000北京
简单继承优缺点
优点:
简单、直观缺点:
传统、不够动态
参考文献《C/C++程序员的Lua快速入门》