在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
lua的设计目标是嵌入式语言,所以和其它动态语言(如python、ruby)相比其自带的库缺少很多实用功能。 好在有lua社区有Penlight,为lua提供了许多强大的功能,接下来的几篇博客,我会简译Penlight的wiki。
目的 常有人说lua不带电池。因为lua的目标是可以运行在各种机器上的简洁语言,(有些机器甚至不 支持布尔系统)。lua类似于操作系统内核(注:即不是完整的系统,只有基本功能),lua的作者 并没有把围绕lua开发完整的生态系统看做自己的职责。这是社区的角色。 软件设计的原则是识别通用模式,并复用。这不但让代码更易管理,而且更易阅读。 Penlight使用了许多编码原则,这样你的代码变得更简洁。如在Lua里通常用{unpack(t)}复制 表,但这只对“小”表有用而且不健壮。因此Penlight提供了tablex.deepcopy(),它可以用来复制 嵌套的表和相关联的元表,所以可以用它复制复杂对象。 lua默认采用这样的错误处理:如果参数类型错误,抛出错误;如果有问题,返回nil,message。 也有些例外的函数,如input.fields默认是返回message并立即关闭程序(可以改变默认方式)。 对脚本而言,与提供堆栈跟踪相比,这是更合适的方式。词法函数为了简化编码,总是返回错误, 必须用pcall封装。 如果你习惯Python的约定,注意lua里的索引从1开始。 lua不建议用table.foreach,而是泛型for,但是使用Penlight提供的高阶函数,它在某些情况下 特别有用。注意tablex.foreach,颠倒了顺序,先传值,之后索引。虽然乖张,符合预期要更好。 Penlight唯一外部依赖是 LuaFileSystem (lfs ),如果你想dir.copyfile在Windows上成功工作 ,你需要 alien 或 LuaJIT 。(如果失败,会调用等效的shell命令)
注入还是不注入 人们很早就意思到大的程序里需要保证命名清晰的方法,如tables (Lua), namespaces (C++) 或modules (Python)。在大公司里很容易遇到命名冲突,在一些简单的语言,如Lua,并没有提 供像C++那样解决命名冲突的详细机制,因此更易遇到。在一小圈朋友里‘Bruce‘是唯一的,不需 要加姓。这取决于你写十多行的脚本,还是上万行的程序。 Penlight提供了正规和非正规两种方式,你可以随意使用。 正规方式: local utils = require 'pl.utils' utils.printf("%s\n","hello, world!") require 'pl' utils.printf("%s\n","That feels better") 正规方式在写模块时更好。 Andrew Starks贡献了另一种方法,很好的在两种方法里取得了平衡。 local pl = require'pl.import_into'() pl表是一个 ‘lazy table’,即按需载入,因此可以使用pl.utils.printf,这样不会污染全局。 如果你在lua5.2里使用 local _ENV,M = require 'pl.import_into' () function answer () -- all the Penlight modules are available! return pretty.write(utils.split '10 20 30', '') end return M
默认把Penlight放在_ENV里,可能会对模块造成意外效果(和 。为了方便和安全,你需要向这个函数传入true,这样module M就和_ENV不一样,只包含导出的 函数。(注:对lua5.2不了解,这句话不解) 你想把pl.stringx里的函数导入到标准库里,可以这么做: require 'pl' stringx.import() require('pl.stringx').import() > require 'pl' > utils.import(math) --把math里的函数直接导入到全局 > = sin(1.2) 0.93203908596723
当第一次require来导入时,utils.import 的参数也可以是字符串。在module里使用时,import会 把符号导入到module的上下文。 对于动态语言,保持全局域简洁是很重要的。 pl.strict模块,引入了简单的强制措施:全局变量必须 声明。如下: > require 'pl.strict' > print(x) stdin:1: variable 'x' is not declared > x = nil > print(x) nil -- mymod.lua local strict = require 'pl.strict' local M = strict.module (...) function M.answer () return 42 end return M 如果你不小心错打成
strict.make_all_strict(_G)
> _1 = func._1 > = List{10,20,30}:map(_1+1) {11,21,31} 另外一个有用的是utils.string_lambda ,也会自动调用 > = List{10,20,30}:map '|x| x + 1' {11,21,31} 少用循环的利弊
local res = {} for i = 1,#ls do res[i] = fun(ls[i]) end sum = utils.memoize(function(n) local sum = 0 for i = 1,n do sum = sum + i end return sum end) ... s = sum(1e8) --takes time! ... s = sum(1e8) --returned saved value! 应用支持
-- animal.lua class = require 'pl.class' class.Animal() function Animal:_init(name) self.name = name end function Animal:__tostring() return self.name..': '..self:speak() end class.Dog(Animal) function Dog:speak() return 'bark' end class.Cat(Animal) function Cat:_init(name,breed) self:super(name) -- must init base! self.breed = breed end function Cat:speak() return 'meow' end class.Lion(Cat) function Lion:speak() return 'roar' end fido = Dog('Fido') felix = Cat('Felix','Tabby') leo = Lion('Leo','African') $ lua -i animal.lua > = fido,felix,leo Fido: bark Felix: meow Leo: roar > = leo:is_a(Animal) true > = leo:is_a(Dog) false > = leo:is_a(Cat) true local class = require 'pl.class' class.Named { _init = function(self,name) self.name = name end; __tostring = function(self) return 'boo '..self.name end; } b = Named 'dog' print(b) --> boo dog Strings:catch(function(self,name) return function() error("no such method "..name,2) end end) Strings:catch(List.default_map_with(string)) ls = Strings{'one','two','three'} asserteq(ls:upper(),{'ONE','TWO','THREE'}) asserteq(ls:sub(1,2),{'on','tw','th'}) cast类型转换,它不产生新对象,而是返回你传入的对象。 local sizes = ls:map '#' --即取长度 asserteq(sizes, {3,3,5}) asserteq(utils.type(sizes),'Strings') asserteq(sizes:is_a(Strings),true) sizes = Vector:cast(sizes) asserteq(utils.type(sizes),'Vector') asserteq(sizes+1,{4,4,6}) utils.type可以返回类中_name属性的字符串。 local MyProps = class(class.properties) local setted_a, got_b function MyProps:_init () self._a = 1 self._b = 2 end function MyProps:set_a (v) setted_a = true self._a = v end function MyProps:get_b () got_b = true return self._b end local mp = MyProps() mp.a = 10 asserteq(mp.a,10) asserteq(mp.b,2) asserteq(setted_a and got_b, true)
|
请发表评论