Lua语言入门(四)

环境的概念

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

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

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

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

a = 1
--改变一个函数的环境,参数1可以为参数本身,也可以是数字,表示当前函数调用栈的层数,参数2表示新的环境table
setfenv(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),...就是传递的name
local M = {}
_G[modname] = M --把M放在全局环境中,让其它地方可以用modname调用该模块
--package.loaded[modname] = M --和末尾的return M 一样的功能

--可定义一系列模块包含的功能

M.add = function(a, b)
 return a+b
end
--

--return M

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

--模块设置 
local modname = ... --其它地方使用require(name),...就是传递的name
local M = {}
_G[modname] = M --把M放在全局环境中,让其它地方可以用modname调用该模块
--package.loaded[modname] = M --和末尾的return M 一样的功能

--导入段
--声明这个模块从外界所需的所有东西
local sqrt = math.sqrt
local io

--改变当前环境,这句话之后就不能访问全局环境中变量了,所以把需要用的外界的在上面先导入进来,注意是local变量存的
_ENV = M

--模块内容
M.add = function(a, b)
 return a+b
end

return 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 - v
end

b = a
a = nil

b: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 o
end

function a.f()
 print("a.f")
end

x = a:new()
 --“:”调用
x.f()

52、继承

a = {} --创建基类a
function a:new(o)
 o = o or {}
 setmetatable(o, self)
 self.__index = self --
 return o
end

function a.f()
 print("a.f")
end

b = a:new() --派生类b

function  b.display()
 print("b.display")
end

c = 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
 end
end

function 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 c
end

--创建新类
mult = createClass()
mult.fun = function()
 print("mult fun")
end

--创建对象
a = mult:new()
a.fun()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值