Lua语言入门(四)

来源:互联网 发布:tf卡数据恢复 编辑:程序博客网 时间:2024/06/05 16:16

环境的概念

45、环境:lua将其所有的全局变量(值、函数、table)保存在一个常规的table中,这个table称为环境,可以认为一个chunk只有一个环境,在lua5.2以后就不允许修改某个函数的环境了。全局变量存在一个叫 _G 的表中。环境的概念是针对全局变量的,对local变量无影响。

利用table访问的元方法可以控制全局变量的访问

--绕过元表,创建全局变量 a ,并赋值为“android”rawset(_G, "a", "android")print(a)
--绕过元表判断是否存在全局变量 varif rawget(_G, var) == nil then print("not declare")end

46、非全局的环境(特只自己创建的环境,不是全局环境(_G))
修改函数的环境:setfenv,注意在lua5.3中去除了setfenv,有_ENV属性代替。

a = 1--改变一个函数的环境,参数1可以为参数本身,也可以是数字,表示当前函数调用栈的层数,参数2表示新的环境tablesetfenv(1, {}) --1表示当前函数,2表示调用当前函数的函数,依次类推print(a) --这样就访问不到 a 了

47、理解非全局环境:定义全局变量,默认被存储在当前环境中的,如果改变了环境,在新环境就没有以前环境下定义的函数变量等。使用全局变量时,不带表前缀(表名.)的,都是默认在当前环境中去找的。

--local x = print --改变环境对local变量无影响x = print --定义x时的全局环境就是“全局环境”_ENV = {} --现在改变环境了,之前定义的全局变量都不在了 ,这个就是非全局环境a = 10 --这里定义的“全局变量 a”,是在当前环境中,也就是 “{}”x(a) --此时就访问不到 x 了,如果 x 是local的就可以访问

非全局环境可以解决名字污染问题,也是lua封装的重要方法之一

模块

48、加载模块
require函数:用于加载一个模块,如果传入的名字找到一个函数,则直接在加载;如果找到一个Lua文件,则用loadfile加载;如果找到一个C程序库,则用loadlib加载。

--local m = require "mod" --mod是模块的名称--print(m.add(1, 2))require "mod"print(mod.add(1, 2))

require查找的路径:存放在变量package.path中,当Lua启动后,便以环境变量LUA_PATH的值来初始化。

判断name模块是否已加载:package.loaded[name],已经加载的模块会放在package.loaded中。

49、编写模块的基本方法

local modname = ... --其它地方使用require(name),...就是传递的namelocal M = {}_G[modname] = M --把M放在全局环境中,让其它地方可以用modname调用该模块--package.loaded[modname] = M --和末尾的return M 一样的功能--可定义一系列模块包含的功能M.add = function(a, b) return a+bend----return M

50、在模块中使用环境:上述的模块基本写法中,整个模块内部是在全局环境中的,如果不小心定义了全局变量,那么这个变量在任何加载该文件的地方都可以直接使用,不需要模块前缀,打破了模块的封装性,名字空间污染。

--模块设置 local modname = ... --其它地方使用require(name),...就是传递的namelocal M = {}_G[modname] = M --把M放在全局环境中,让其它地方可以用modname调用该模块--package.loaded[modname] = M --和末尾的return M 一样的功能--导入段--声明这个模块从外界所需的所有东西local sqrt = math.sqrtlocal io--改变当前环境,这句话之后就不能访问全局环境中变量了,所以把需要用的外界的在上面先导入进来,注意是local变量存的_ENV = M--模块内容M.add = function(a, b) return a+bendreturn M

面向对象编程

51、类:在Lua中没有类的概念,每个对象只能自定义行为和形态。但可以用原型来模拟类的概念,因为在会在表的原型中查找它所没有的操作,就可以认为是原型定义了一系列操作,创建一个表并设置原型就近似创建了“对象”。

让 a 的__index属性 等于 b,这样a 就会在 b 中查找所有它没有的操作,a 可以 称为 b的对象。

setmatatable(a, {__index = b})

“:”和“.”的区别:“:”会隐式的传递当前调用者

a = {balance = 0}function a:f(v) --a:f(v) 等价于 a.f(self, v) self.balance = self.balance - vendb = aa = nilb:f(1) --b:f(1) 等价于 b.f(b, 1)
面向对象的写法:
a = {}function a:new(o) --“:”定义 o = o or {} setmetatable(o, self) self.__index = self --让o的元表 self的__index属性等于自身,意味着 o 就会在 self 中查找所有它没有的操作 return oendfunction a.f() print("a.f")endx = a:new() --“:”调用x.f()

52、继承

a = {} --创建基类afunction a:new(o) o = o or {} setmetatable(o, self) self.__index = self -- return oendfunction a.f() print("a.f")endb = a:new() --派生类bfunction  b.display() print("b.display")endc = b:new() --创建b类的对象 c

所以啊,lua中类和对象本身没有区别,你可以叫 b、c 是对象,也可以认为它们是派生类。

53、多重继承:如果__index是一个函数,之前学过,当访问一个表中不存在的操作时,就会调用元表中__index元方法返回结果。那么多重继承就是利用在 __index元方法中,查找所有继承的基类,是否存在相应的操作。

local function search(k, plist) for i=1,#plist do  local v = plist[i][k]  if v then return v end endendfunction createClass(...) local c = {} local parents = {...} setmetatable(c, {__index = function(t, k)   return search(k, parents)  end}) --c.__index = c function c:new(o)  o = o or {}  setmetatable(o, c)  c.__index = c  return o end return cend--创建新类mult = createClass()mult.fun = function() print("mult fun")end--创建对象a = mult:new()a.fun()
0 0
原创粉丝点击