LUA中最基本的结构是table,用table来描述对象的属性。lua 中的 function 可以用来表示方法。
那么LUA中的类可以通过 table + function 模拟出来。
Student = {
age = 1,
growUp = function()
-- print(age) 这样写与表中没有任何关系,他打印age这个全局变量
-- 一定要调用表名.属性来指明是谁做的
print(Student.age)
end
}
-- 声明表之后 ,仍可以在表外生命变量和方法
Student.name = "Name"
Student.Speak = function()
print("说话")
end
-- 第三种函数的声明方法
function Student.Speak2()
print("说话2")
end
-- 使用冒号 : 来将调用时冒号前的变量作为self
function Student:Speak3()
print(self.name.."说话3")
end
print(Student.age)
Student.Speak()
Student.Speak2()
Student:Speak3() -- Student 作为self
--[[输出结果
1
说话
说话2
Name说话3
--]]
类都是基于table来实现的
Object = {}
Object.id = 1
-- 冒号 会自动调用这个函数的对象,作为第一个参数传入
function Object:new()
-- self 表示我们默认传入的第一个参数
local obj = {}
--__index当找不到自己的变量时就去元表当中查找__index指向的内容
self.__index = self
setmetatable(obj, self)
-- 返回出去的本质上是表对象
return obj
end
function Object:Test()
print(self.id)
end
local myObj = Object:new()
print(myObj)
print(myObj.id)
myObj:Test()
--[[输出
table: 00B09730
1
1--]]
myObj就是个空表,但是因为指定了__index所以会返回Object中的id
继承是指一个对象直接使用另一对象的属性和方法。可用于扩展基础类的属性和方法。
以下演示了一个简单的继承实例, 沿用Lua封装中的代码
function Object:subClass(className)
-- 大G表存储了所有的非local变量,相当于创建了一个名为className的空表
_G[className] = {}
-- 写继承相关的规则
local obj = _G[className]
-- 将元表的index设为自己,这样obj找不到某个值时会去传入的self查找
self.__index = self
-- 给子类定义base属性代表父类
obj.base = self
setmetatable(obj, self)
end
Object:subClass("Person")
local p1 = Person:new()
print(p1.id)
p1.id = 100
print(p1.id)
p1:Test()
Object:subClass("Monster")
local m1 = Monster:new()
print(m1.id)
m1.id = 200
print(m1.id)
m1:Test()
--[[输出结果
1
100
100
1
200
200--]]
引用参数self:指向调用者自身,相当于this指针
**冒号引用:**self指针指向冒号之前的对象,相当于把将独显赋值给self。如果使用 . 的话,那么self就为nil
总之就相当于 冒号定义的函数如果用点来调用,那么第一个参数就视为self
myclass = {age = 10, name="aa"} function myclass:fun(p) print(self) print(self.age) print(p) end myclass:fun("22") --[[输出table: 00D69810 10 22]]-- myclass.fun("22") --[[输出22 nil nil]]-- myclass.fun(myclass, "22") --[[输出table: 00F298B0 10 22]]--
多态:不同表现相同行为,还是沿用之前的部分代码
Object:subClass("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:subClass("Player")
function Player:Move() -- 重写同名方法
-- 因为lua继承是我们自己实现的,所以也就不能用base.Move()这种形式来调用父类的方法
self.base:Move() -- 使用冒号调用,就相当于把Gameobject作为self传入方法中,就相当于所有实例公用了同一张表,这是不行的
--正确调用方法
self.base.Move(self) -- 将调用者传入作为Move方法中的self
end
local player1 = Player:new()
player1:Move() -- self 指向player1
local player2 = Player:new()
player2:Move() -- self 指向player2
--[[
错误调用的输出 1 1 2 2
正确调用的输出 1 1 1 1
--]]
定义:包是一种组织代码的方式。
-- test.lua
print("successful")
A = "123"
local locA = "234"
-- main.lua
require("test") -- 加载执行test.lua脚本
print(A)
print(localA)
--[[输出结果
successful
123
nil
]]--
package.loaded["脚本名"]
,返回值是该脚本是否被执行的booleanpackage.loaded["脚本名"] = nil
如果我们想要获取另一脚本的local变量,我们可以return出来。比如在上诉的 test.lua
中 添加return localA
然后再 main.lua
中创建变量接受他 testLocalA = require("test")
可以使用大G表,所有声明的全局变量都将会存储在里面,local 变量不会在里面
for k,v in pairs(_G) do
print(k,v)
end
一般在一个Lua文件内以module函数开始定义一个包。module同时定义了一个新的包的函数环境,以使在此包中定义的全局变量都在这个环境中,而非使用包的函数的环境中。
自定义包
-- mypack.lua
module(..., package.seeall) --定义包,包的名字与定义包的文件的名字相同,并且在包的函数环境里可以访问使用包的函数环境
ver = "0.1 alpha"
function aFunInMyPack()
print("Hello!")
end
_G.aFuncFromMyPack = aFunInMyPack
测试代码
-- hello.lua
local pack = require "mypack" --导入包,导入的包必须被置于包路径(packagepath)上。包路径可以通过package.path或者环境变量来设定
print(ver or "No ver defined!")
print(pack.ver)
pack.aFunInMyPack()
print(aFunInMyPack or "No aFunInMyPack defined!")
aFuncFromMyPack()
--[[输出结果
No ver defined!
0.1 alpha
Hello!
No aFunInMyPack defined!
Hello!
--]]
require 用于使用模块,module 用于创建模块。
简单的说,一个模块就是一个程序库,可以通过 require 来加载。然后便得到了一个全局变量,表示一个 table。这个 table 就像是一个命名空间,其内容就是模块中导出的所有东西,比如函数和常量
如果不用module 函数创建包
local M = {};
local modelName = ...;
_G[modelName] = M;
function M.play()
print("那么,开始吧");
end
function M.quit()
print("你走吧,我保证你不会出事的,呵,呵呵");
end
return M;
----或者是下面这样----
local M = {};
local modelName = ...;
_G[modelName] = M;
package.loaded[modname] = M
setfenv(1, M);
function play()
print("那么,开始吧");
end
function quit()
print("你走吧,我保证你不会出事的,呵,呵呵");
end
return M;
在调用 module 函数时,多传入一个 package.seeall 的参数,相当于 setmetatable(M, {__index = _G})