- 论坛徽章:
- 5
|
本帖最后由 starwing83 于 2012-10-09 23:04 编辑
回复 44# OwnWaterloo
range的“stateless iterator”写法(效率最高,应用最狭窄):
- local function range_helper(n, i)
- if i <= n then return i + 1 end
- end
- function range(n)
- return range_helper, n, 0
- end
复制代码 注意,这里一个闭包都没有的。
如果数据量大,使用方式可以不变。也就是一个抽象层而已了。而table和closure都是很好的抽象层。
假设我需要这个stateless iterator变成闭包,就需要一个函数:
- function iter(f, s, init)
- local t = {init}
- return function()
- t = {f(s, table.unpack(t))}
- return table.unpack(t)
- end
- end
复制代码 注意这个写法很浪费,因为每次调用都会产生一个表。更高效的写法是在C API里面写。可以做到每次调用都不产生内存。
有了iter函数,那么就可以这样:
map(f, iter(ipairs(t1)), iter(range(10)))
iter不一定要在这里出现,甚至可以让iter函数是一个处理stateless iterator generator的函数,即抽一个地方:
- if data_is_too_big then
- map = iter(map)
- end
复制代码 iter负责把表驱动的改为用闭包驱动的。这是很简单的。
好了,这是用闭包/stateless iterator作为接口。如果用表作为接口:
- function range(n)
- return setmetatable({}, {__index = function(t, k)
- if k < n then return k end
- end})
- end
复制代码 这个写法照样是示例性的,metatable和__index函数都是可以stateless的。这没有问题。
我们可以通过lazy_table函数,做到closure/stateless到table的转换。
- if data_is_too_large then
- map = lazy_table(map)
- end
复制代码之前map接受table,返回table之前的map接受闭包,返回闭包,我们可以让现在map接受table(这需要所有的工具都被lazy_table包裹),但是返回的是个lazy_table。即惰性的table。
我们还可以设计接口,让接受表返回表的map变成接受闭包返回闭包的。方案也是上面的lazy_table,它可以让map本身接受的表实际上以前是个闭包,而返回的表实际上依然是个闭包。
这就是Lua中的序列操作和惰性操作的基本方式。有两套接口:函数和表,两套接口都是可以互相转换的,不存在兼容性问题。
|
|