lua中利用访问控制,自动载入lua文件,提升开发效率。

本文介绍了如何在Lua中实现访问控制,以避免非法访问带来的问题,并探讨了通过自动载入机制提高开发效率的方法。通过ImmutableMetatable类,可以实现对未定义属性或方法的错误处理,并在读取时自动加载相应的模块。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

lua语言非常灵活,开发者发挥的空间很大,模拟oop,使用xml等,此篇文章将向大家介绍如何添加访问控制,不用此来实现 lua自动载入机制 提示开发效率。

类似java、as3等语言,访问没有定义的属性、方法、或者非公有属性时会报错,再编译阶段这些错就能暴漏出来,lua则不能,这些访问对他都是合法的,如果你使用lua做一些较大型的开发,这种能合法调用但不合法的访问,会给你带来很多坑,访问控制作者认为还是非常有必要的。

lua中导入一个moudle,常规做法是使用require(“**.**.**”),lua自动载入机制目的就是省略这一步,一定程度上有助于开发效率的提升。

先来看看访问控制类 

ImmutableMetatable.lua

--- Author: terran
--  Date: 27/9/2013 15:03	

local ImmutableMetatable = {};
local M  = ImmutableMetatable;

function declare (item,name, initval)
   rawset(item, name, initval)
   item.ImmutableMetatable__declaredNames[name] = true
end

function  M.__newindex(t, n, v)
	if(rawget(t,"ImmutableMetatable__declaredNames") == nil) then 
		error("attempt to write to undeclared var "..n, 2)
		return;
	end
	if not t.ImmutableMetatable__declaredNames[n] then
		local handler =  t.ImmutableMetatable__writeErrorHandler;
		if(handler == nil or not handler(t, n, v)) then
			error("attempt to write to undeclared var. "..n, 2)
		end
	else
		rawset(t,n,v)
	end
end

function M.__index(t, n)
	if(rawget(t,"ImmutableMetatable__declaredNames") == nil) then
		error("attempt to read undeclared var. "..n, 2)
		return;
	end
	if not t.ImmutableMetatable__declaredNames[n] then
		local handler = t.ImmutableMetatable__readErrorHandler;
		if(handler == nil or not handler(t, n)) then
			error("attempt to read undeclared var. "..n, 2)
		else
			return t[n];
		end
	else
		return nil
	end
end

function ImmutableMetatable.extend(item,readErrorHandler,writeErrorHandler)
	declare(item, "ImmutableMetatable__declaredNames", {});
	declare(item, "ImmutableMetatable__readErrorHandler", readErrorHandler);
	declare(item, "ImmutableMetatable__writeErrorHandler", writeErrorHandler);
	
	return setmetatable(item,M);
end


return M;

该类的使用比较简单:比如

local a = {};

ImmutableMetatable.extend(a,readErr,wirteErr);

这样在对a进行不存在定义的访问时,就能捕捉到错误。

比如:调用print(a.b),而a中并没有属性b的定义,则会回调readErr函数,做一些自定义的处理,如果该回调函数返回false,则直接抛出异常,否则正常继续;执行a.b = 12,同样的原理,会调用wirteErr回调函数。


lua文件的自动载入机制就是利用这个访问控制的readErr回调函数来实现的。接下来可以看看具体的实现代码。机制核心类

        ImmutableMetatable = require("core.ImmutableMetatable");
	local luaClasses = require("LuaClasses");
	
	local readErr = function(t,n)
		if(luaClasses[n] ~= nil) then
			local name = luaClasses[n];
			declare(t,n,require(luaClasses[n]));
			return true;
		end
		return false;
	end
	
	ImmutableMetatable.extend(_G,readErr);

可以看到ImmutableMetatable直接作用到了全局(_G),这样访问任何一个未定义的全局变量或方法时都会跑到readErr函数中,此时我们可以检查该变量是否是我们的一个moudle,如果是,自动require进来,这样就完成了整个过程。代码中的LuaClasses是所有lua文件的枚举类,当然也不需要去手动维护,有一个小工具自动生成,先来看看他得格式:

local LuaClasses = {};
LuaClasses.Config = "Config";
LuaClasses.AppBase = "core.AppBase";
LuaClasses.audio = "core.audio";
LuaClasses.BindingUtils = "core.bind.BindingUtils";
LuaClasses.BindObject = "core.bind.BindObject";
LuaClasses.Alert = "core.components.flex.Alert";
LuaClasses.ArrayCollection = "core.components.flex.ArrayCollection";
LuaClasses.BasicLayout = "core.components.flex.BasicLayout";
return LuaClasses

结合自动载入的核心逻辑,如果你直接访问ArrayCollection,程序会自动到LuaClasses中找到对应“core.components.flex.ArrayCollection”,这个值即为ArrayCollection.lua文件的存放路径。

下面给出LuaClasses.lua文件的生成工具,也是用lua下得,在mac下使用。

--------------------------------
--------------------------------
-- 此工具为工程lua classes文件生成工具,可遍历
-- 指定目录,将所有lua文件遍历输出到LuaClasses.lua中。 
-- 用法:
-- 1、命令行输入: lua LuaClassesMaker.lua
--
--Author: terran.tian
--Date  : 9/13/2013 16:35
---------------------------------
---------------------------------

local function split(str, delimiter)
    if (delimiter=='') then return false end
    local pos,arr = 0, {}
    for st,sp in function() return string.find(str, delimiter, pos, true) end do
        table.insert(arr, string.sub(str, pos, st - 1))
        pos = sp + 1
    end
    table.insert(arr, string.sub(str, pos))
    return arr
end

local function scandir(directory)
   local i, t, popen = 0, {}, io.popen
   local cmd = string.format('find %q -name  "*.lua" -o -name "*.xml"' ,directory)
   print("cmd: "..cmd)
   for filename in popen(cmd):lines() do 
      i = i + 1
      t[i] = filename
   end
   
   return t
end

local function reloadquest(dir,foldName)
   local file=scandir(dir)
   
   for i=1,#file do
   	  local filename = string.gsub(file[i],dir,foldName)
      print(filename)
   end
end

local function writeFile(path,data)
	
	file = io.open(path,"w")
	file:write(data)
	file:close() 
end

local function main()
	local folder = "../assets/scripts/";
	local files = scandir(folder);
	local tempArr = split(folder,"/");
   	local folderName = tempArr[#tempArr];
   	
   	local content = "--[[\
   	This file was generated automatically\
   	Any modifies will by revert during nect generation.\
   	Any question ,contact terran.tian@foxmail.com for help\
   	%q\
   	]]\n"
   	content = string.format(content,os.date("%c"));
   	content = content.."local LuaClasses = {};\n"
   
	for i=1,#files do
   	  local filepath = string.gsub(files[i],folder .."/","")
   	  tempArr = split(filepath,"/");
   	  local filename = split(tempArr[#tempArr],".")[1];
   	  if(filename ~= "init") then
	   	  filepath = string.gsub(filepath,"/",".");
	   	  filepath = string.gsub(filepath,".lua","");
	   	  local record  = string.format('LuaClasses.%s = %q;\n',filename,filepath);
	   	  content = content..record;
	      print(record);
      end
   	end
   	
   	content = content.."return LuaClasses;"
   	
   writeFile(folder.."/LuaClasses.lua",content)
end
main();


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值