九.面向对象编程
在lua中,可以使用table来表示"类":
--基类Account --定义变量balance --定义方法new,deposit,withdraw --self是lua的关键字,类似于this,指调用者本身,如Account:new,self就是指Account;如a:deposit,self就是指a --Account:deposit(v)的另一种写法为:Account.deposit(self, v) --调用时,就要写成:a.deposit(a, v)的形式 Account = {balance = 0} --设置balance默认值为0 function Account:new(o) --构造函数,名字可随意取 o = o or {} --若o为nil,则创建一个table setmetatable(o,self) --设置o的元表为self,当调用Account:new时,self等于Account self.__index = self --当在o中找不到key时,lua会找元表中__index对应的函数或者table return o end function Account:deposit(v) self.balance = self.balance + v end function Account:withdraw(v) if v > self.balance then error "insufficient funds" else self.balance = self.balance - v end end ---------------------------------------------------------------- a = Account:new({balance = 200}) a:deposit(100) --a没有deposit字段,所以会使用Account的deposit方法 print(a.balance) --300 b = Account:new() print(b.balance) --0 c = b:new({limit = 1000}) --b从Account中继承了new,而b中的new方法,self代表的是b --因此,c的元表为b,b中的__index字段为b,c继承b,b继承Acount c:deposit(500) print(c.balance) --500 ---------------------------------------------------------------- --[[ b可以重写从Acount中继承的方法 ]] function b:getLimit() return self.limit or 0 end function b:withdraw(v) if v - self.balance >= self:getLimit() then error "insufficient funds" else self.balance = self.balance - v end end c:withdraw(700) --c会先从b中找withdraw print(c.balance) -- -200 print(c:getLimit()) --1000 ---------------------------------------------------------------- function c:getLimit() return self.balance * 0.1 end print(c:getLimit()) -- -20
十.模块与包
require的使用
1.使用的编辑器是LuaEditor(v6.30),需要设置选项 / 编译调试设置,先取消勾选"直接以xxx",然后设置脚本工作目录(即lua脚本的目录),最后重新勾选"直接以xxx"
2.在桌面新建一个文件夹,然后如图,然后在another下建一个Test2.lua
3.
--Test.lua print("Test"); function hehe() print("hello"); end
--Test2.lua print("Test2"); function hehe() print("hello2"); end
--TestRequire.lua print(package.path) --输出默认的搜索模式 require("Test") package.path=package.path..";.\\another\\?.lua;" require("Test2") require("Test") --不再执行
.\?.lua;D:\Program Files\LuaEditor6.30\lua\?.lua;后面略,其中分号是分隔符
当require("Test")时,lua会用Test来替代上面的问号,从而变成:
.\Test.lua;D:\Program Files\LuaEditor6.30\lua\Test.lua;
意思就是从当前目录、D:\Program Files\LuaEditor6.30\lua等路径逐一搜索Test.lua这个文件
其中require会在初次加载时执行一次该lua文件,require第二次时,是不会再加载的
相对路径:
";.\\another\\?.lua;" .\的意思是当前目录,..\是上一层目录
绝对路径:
package.path=package.path..";D:\?.lua;"
4.编写模块
--LuaEditor1.lua local M = {} --complex是供外部调用的接口,M是内部table,当修改接口名时 --只需修改complex和return,内部的函数定义就不需修改了 complex = M function M.new(r,i) return {r=r,i=i} end M.i = M.new(0,1) function M.add(c1,c2) return M.new(c1.r+c2.r, c1.i+c2.i) end function M.sub(c1,c2) return M.new(c1.r-c2.r, c1.i-c2.i) end function M.mul(c1,c2) return M.new(c1.r*c2.r, c1.i*c2.i) end function M.div(c1,c2) return M.new(c1.r/c2.r, c1.i/c2.i+M.inv(1)) end function M.inv(c) local n = c + 1; return n end --如果没有返回值,默认会返回一个布尔类型,表示该模块是否加载过 return complex
local o = require "LuaEditor1" a = o.new(1,2); b = o.new(3,4); print(o.add(a,b).r..","..o.add(a,b).i); print(o.div(a,b).r..","..o.div(a,b).i); print(complex.new(10,20).i);--]]