当前位置: 首页 > 工具软件 > Lua Fun > 使用案例 >

lua面向对象

相温文
2023-12-01

简单的类实现

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
--]]

Lua封装

类都是基于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继承

继承是指一个对象直接使用另一对象的属性和方法。可用于扩展基础类的属性和方法。

以下演示了一个简单的继承实例, 沿用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]]--

Lua多态

多态:不同表现相同行为,还是沿用之前的部分代码

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
--]]

Lua包

定义:包是一种组织代码的方式。

简单的多脚本执行

-- test.lua
print("successful")
A = "123"
local locA = "234"

-- main.lua
require("test") -- 加载执行test.lua脚本
print(A)
print(localA)

--[[输出结果
successful 
123
nil
]]--
  • 脚本不仅会加载,还会执行
  • 可以使用package.loaded["脚本名"],返回值是该脚本是否被执行的boolean
  • 如果想要卸载脚本,package.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})

 类似资料: