Lua 安全调用 metatable 的简单应用

事情的经过

我们的项目中存在好几个战斗界面,不过界面中的内容略有不同。跟同事出去吃饭的时候,他问我。我们现在的战斗界面。有很多是重复的,但是也有偶尔几个地方不太一样。我在战斗过程中驱动这些界面的时候。还需要判断一下有没有这个函数,然后在选择调用它。比较麻烦,你说怎么样才能更好的规划这件事情呢?我第一个想到的就是抽离出来一个UI的父层对象。然后父层对象实现所有的函数。然后让父层函数hook住具体的页面。然后判断具体的页面究竟有没有这个函数,如果存在这个函数那么调用,否则什么都不做就行了。不过,我突然间意识到,我们似乎存在更简单的方式来解决这个问题。

基础知识

Lua中本身是没有继承这种概念的,他里边大部分内容都是通过table来解决的。在最开始学习Lua的时候了解到。他的继承关系实际上是基于metatable的__index来实现的。原理就是当在这个table中没有找到的函数或者属性他就会从metatable中的__index属性中来找。(顺便提一句其实Cocos2dx lua中的继承类都用用的同一个,也就是内存继承,主要继承来的是对应的函数。不过这个扯得有点远了)。上文中提到的查找会分情况来定,如果metatable中的__index为nil时,则不找了,直接返回nil。如果metatable中的__index是一个table的话就尝试从这个table中匹配相关的内容,如果这个table也没有那么就按照这个规则继续往上找(如果很不幸,你的metatable的__index指向的对象就是你自己的话,那么就会进入死循环)。还有第三种情况,如果metatable的__index是一个function那么,就会以这个函数的返回结果作为查找结果(按照这个原理,你可以返回任何东西。甚至可以实现多重继承,听起来很有诱惑力,不过最好不要这么做,因为比较麻烦并且lua不是那种守规矩的语言)。

实现的思路

创建一个Table,然后让他hook住对应的实际对象,然后重写对象metatable中的__index为一个函数,让这个函数返回对应的调用函数,在返回的函数中尝试查找源数据的对应函数,如果存在就调用,不存在就什么也不做。

具体的代码

local SafeCall = {}

function SafeCall:create(souce)
    local instance = {}
    setmetatable(instance, {__index = function(self, aname)
        local attribute = self.__Souce[aname]
        if type(attribute) == "function" or type(attribute) == "nil" then
            return function(...)
                if attribute then
                    local args = {...}
                    if #args > 0 and args[1] == self then
                        table.remove(args, 1)
                        return attribute(self.__Souce, unpack(args))
                    else
                        return attribute(...)
                    end
                end
            end
        else
            return attribute
        end
    end})
    instance.__Souce = souce
    return instance
end

function SafeCall.new(souce)
    return SafeCall:create(souce)
end

kunpo.SafeCall = SafeCall
return SafeCall
时间: 2024-08-08 01:26:15

Lua 安全调用 metatable 的简单应用的相关文章

Lua中调用C函数

Lua利用一个虚拟的堆栈来给C传递值或从C获取值.每当Lua调用C函数,都会获得一个新的堆栈,该堆栈初始包含所有的调用C函数所需要的参数值(Lua传给C函数的调用实参),并且C函数执行完毕后,会把返回值压入这个栈(Lua从中拿到C函数调用结果). 于此相关的C API有几个比较重要的定义如下: (1)typedef struct lua_State lua_State; lua虚拟机(或叫解释器),可以理解为一个thread,和一个完整的Lua虚拟环境的执行状态. (2)typedef int

Lua中调用C函数(lua-5.2.3)

Lua可以调用C函数的能力将极大的提高Lua的可扩展性和可用性. 对于有些和操作系统相关的功能,或者是对效率要求较高的模块,我们完全可以通过C函数来实现,之后再通过Lua调用指定的C函数. 对于那些可被Lua调用的C函数而言,其接口必须遵循Lua要求的形式,即typedef int (*lua_CFunction)(lua_State* L). 简单说明一下,该函数类型仅仅包含一个表示Lua环境的指针作为其唯一的参数,实现者可以通过该指针进一步获取Lua代码中实际传入的参数.返回值是整型,表示该

Lua——3.元表Metatable

lua的metatable也是一个普通的表,lua提供metatable的功能,主要有一下几种作用: 控制对 table 的访问 为 Lua 函数库提供支持 重载算数运算符和关系运算符的行为 1.使用metatable控制对table的访问 当查询table的某个键的时候,如果该table的这个键没有值,那么Lua就会寻找该table的metatable中的__index元方法:如果__index指向一个table,Lua会在此table中查找相应的键, 并且,__index也可以指向一个方法

Unity3D热更新之LuaFramework篇[05]--Lua脚本调用c#以及如何在Lua中使用Dotween

在上一篇文章 Unity3D热更新之LuaFramework篇[04]--自定义UI监听方法 中,我对LuaBehaviour脚本进行了扩展,添加了两个新的UI监听方法,也提到最好能单写一个脚本处理此事.本篇文章就来继续这个工作. 从Lua中调用C#代码 1.创建UI监听脚本 打开之前的工程,在Assets/LuaFrameworks/Scripts/Common下,创建一个UIEventEx.cs脚本,将LuaBehaviour.cs中的AddButtonClick以及AddInputFiel

Lua中调用 cocos2d-x 的滑动条/滚动条 ScrollView

 ScrollView 我想玩儿过手机的朋友对滑动条都不陌生吧,(旁边: 这不是废话么???? )   那好吧,废话不多说直接开始ScrollView吧 local m_BaseNode  -- 主场景 local CreateScroll    -- 房间分级滑动视图 local CreateStageNode   -- 创建节点 local m_ScrollView              -- 滑动层变量 local m_Inner     -- 内容器 local addScrol

LUA脚本调用C场景,使用C API访问脚本构造的表

LUA调用C lua解析中集成了一些系统服务, 故脚本中可以访问系统资源, 例如, lua脚本可以调用文件系统接口, 可以调用数学库, 但是总存在一些lua脚本中访问不到的系统服务或者扩展功能, 如果这些系统服务或者扩展功能是使用C语言实现, 那么可以, 使用lua库的对C库的封装方法, 将其中功能封装成lua 接口, 这样脚本就调用这些lua接口调用这些功能. ------- 这种情况,是以lua脚本作为宿主程序. C调用LUA 另外一种场景,是C程序作为宿主程序, 调用LUA脚本, 例如将l

Rsession让Java调用R更简单

Rsession让Java调用R更简单 R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大. R语言作为统计学一门语言,一直在小众领域闪耀着光芒.直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器.随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长.现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言. 要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥

Lua中“.”调用方法与“:”调用方法的区别

Lua中"."调用方法与":"调用方法的区别:                                                                                                                         一.概述 学lua的时候有一个迷惑点,就是搞不清楚'.'与':'调用方法的区别,今天很早就起来看了看一个大牛的视频讲解,才顿悟了:'.'调用和':'实际是传递参数的个数不同而已,':

Discuz! X2.5 添加自定义数据调用模块(简单方法)

转:http://521-wf.com/archives/46.html Discuz! X2.5 添加自定义数据调用模块(简单方法) Discuz!X系列的diy功能还是相当不错的,在对其进行二次开发的过程中,或许需要加入新的数据调用模块,这样可以使你开发的功能模块也像原来的模块一样,只需要点点鼠标,填写一些简单的信息,就可以在各个页面的各个位置显示你想显示的数据啦. 以下就目前最新版X2.5做一个简答的介绍:大致可以分为以下三个步骤:一.添加数据调用程序二.后台更新diy模块分类缓存三.添加