打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
云风的 BLOG: 给 Lua 增加参数类型描述

给 Lua 增加参数类型描述

Lua 的函数定义是没有参数类型信息的。这些信息在跨语言的模块化设计中非常有价值。因为跨语言的方法调用通常需要做列集(Marshaling) 的操作,缺乏类型信息很难完成这个工作。同样的需求在做 RPC 调用的时候也很重要。

感谢 Lua 简洁的 metatable 的设计,我们可以用一个简单的方法自然的描述出 Lua 函数的调用参数类型,又无损性能。

一开始,我们先回顾一下在 Pil 中推荐的类实现方法。通常我们可以把方法列表(对应于 C++ 中的虚表)放在一个 table 中,然后把这个 table 作为一个 metatable 的 __index 方法,并把 metatable 附加到一个 table 上,就生成了简单的对象。我喜欢这样做:

foo={}function foo:foobar(n)    print(self)    return n*nendfoo={__index=foo}function create(class,obj)    return setmetatable(obj or {}, class)       endt = create(foo) -- 构造一个 foo 对象t:foobar(100)   -- 测试 foobar 方法

当然还有很多看起来更 cool 、更 OO 、更 C++ 的方法来在 Lua 下模拟一个类机制。云风以前也做过一个 ,其实后来还做过,或是见过身边认识的人做的“更漂亮”。只是请小心:Lua 不是 C++ 。实现一个超级 OO 的 Lua 代码风格跟解决问题是两件事,切莫迷失在这些语言技巧中。

有时候我喜欢这样定义成员函数:

local foo={}setfenv(function ()    function foobar(self,n)        print(self)        return n*n    endend,foo)()for _,v in pairs(foo) do setfenv(v,_G) end

利用一个匿名函数,设置独立的 table 做为环境,有时可以方便许多。写起来更自由一些。这种利用独立环境的技巧有时也用来模拟类似 pascal 中的 with

下面是我们的正题:我们可以在此基础上给函数定义加上参数类型申明。

看起来函数定义的代码是这样的:

setfenv(function ()    def.foobar(table,number,    function (self,n)        print(self)        return n*n    end)end,foo)()

这次的函数定义是用 def.function_name 达到的,并且把类型信息独立一行来写。第一行的类型名(table,number),第二行才是参数名(self,n)。

def table number string 这些可以在环境中定义好,作为这套体系中的保留字。它们可以为参数类型系统服务。def 可以是带元方法的空表,通过 __index 元方法捕获 . 后面的字符串参数。这样: 让 del.foobar 产生一个函数用来在环境中设置一个方法,并记录正确的类型信息(供别的框架设施使用)。如果你想在调试期做更强的类型检查,可以给注册的函数 function (self,n) 加一个壳,检查每个传入参数的类型是否匹配。甚至可以实现 Eiffel 那样的调用契约。


云风在下面给出一个简单但完整的实现。(比上面更多出记录了参数名字,语法是 def.foobar(table.self,number.n, 这些信息对于模块的方法自提供文档很有好处)

function test()    def.foobar(table.self,number.x,number.y,string.name,table.arg,    function(self,x,y,name,arg)        print(self)        return x+y    end)endlocal meta_arg_tostring={    __tostring=function (t) return t[1].." "..t[2] end}local function make_type(typename)    return setmetatable({typename},{        __tostring=function(t) return typename end,        __index=function(t,k) return setmetatable({typename,k},meta_arg_tostring) end,    })endlocal meta_type={__index=function(t,k) return k end }local const_table = function (t,k,v) error "const table" endlocal type_gen=setmetatable({    number=make_type "number",    boolean=make_type "boolean",    string=make_type "string",    table=make_type "table",    def=setmetatable({},{        __index = function (t,k)            return function(...)                local vtbl=getfenv(3)                vtbl.__meta[k]=arg                vtbl[k]=setfenv(arg[#arg],_G)                print(k,unpack(arg))    -- 输出函数的原型信息            end        end,        __newindex = const_table    })},{__index=_G,__newindex = const_table } )local class_vtbl = setmetatable ({},{__index=function (t,k)    local ret={ __meta={} }    local gen=setfenv(k,type_gen)    setfenv(function () gen() end,ret)()    ret={ __index=ret }    t[k]=ret    return retend})function create(class, obj)    return setmetatable(obj or {},class_vtbl[class])endlocal obj=create(test)print(obj:foobar(1,2))

以上的代码可以直接在 lua 解释器中运行:将输出结果

foobar  table self      number x        number y        string name     table arg       function: 003E7C38table: 003ED0D83

不多做解释了,弄明白原理的话,可以做更复杂的事情。比如模拟一个 enum,在函数定义里写 enum { "one","two","three" } 。或是增加返回值的描述,建议用语法:def(typename,typename,...).foobar(typename.arg1,typename.arg2)

甚至提供更强的,类似 COM 的接口描述:def.foobar(typename.in_out.arg1,typename.out.arg2)

云风 提交于 October 31, 2008 10:38 PM | 固定链接

Comments

请教一个问题:

function ( string str )


end

怎样改造lua,能支持这种方式? 有这种需求的原因是:

lua是弱类型,动态执行的,这时,在数十万行lua代码的项目中(数十人的团队), 参数在函数的多层调用中,想要知道是什么含义或取值或类型,已经很难追踪了.这是,可能需要如下一些特性:

变量要声明(类型也声明),不能随手使用,否则维护人员或版本迭代修改的开发人员,要吐血;
传参数要声明类型.


比如:

num = number;
num = 0;

str = string;
str = "hello";

function test ( string str, table tb1 )

--do something.

end

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【转贴】Lua 编程技巧
Lua学习之function
Lua丨函数中的可变参数(返回多个参数)~arg的用法
Skywind InsideVimScript 五分钟入门(翻译)
Step By Step(Lua基础知识)(转)
jQuery中$(function()与(function($)等的区别详细讲解
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服