浏览 3529 次
锁定老帖子 主题:方括号感想
精华帖 (0) :: 良好帖 (7) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-06-10
最后修改:2009-06-10
p.call a, b p.(a, b) p.[] a, b p[a, b] 其中,方括号语法的接口和 Hash 相同。原因用一句话表达: 函数是一种映射(Map)。 Hash 映射和 Proc 映射区别在于: Hash 带有缓存机制,而 Proc 不缓存结果。 将 Proc 改造成带缓存的映射,只需要: Hash.new {|h, k| h[k] = p[k]} 为使代码更易懂,改造一下 Proc,增加 memoise 方法: class Proc def memoise Hash.new {|h, k| h[k] = self[k]} end end 使缓存失效,用 Hash 的内置函数就够了,例如: p = proc {|x| x*2}.memoise p[3] # => 6 p[4] # => 8 p # => {3=>6,4=>8} p.delete 3 # 删除这个 key 对应的缓存 p # => {4=>8} p.clear # 删除所有缓存 p # => {} 这种缓存方式的缺点是 Proc 只允许一个参数,希望以后能改善一下 Hash.new 和 Hash.[] 的写法 …… 对于多进程的应用,这个缓存方式查找比全局缓存略快,但命中率低,也没法通知别的进程缓存失效(有是有,不过就失去简单性,变成 cache 框架了……)。 如果 Proc 是 pure 函数,如 route helper,这个缓存方式就很方便。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-06-10
最后修改:2009-06-10
那要不要给memoize生成的Hash加个call方法让它跟Proc更像?顺便把arity还是啥的属性设成1 toka
|
|
返回顶楼 | |
发表时间:2009-06-10
最后修改:2009-06-10
…… 好吧,继续改造:
class Proc module ProcLike def call x; self[x]; end # 有了 call 自动产生 .() 方法 def arity; 1; end def is_a? klass; klass == Proc; end alias kind_of? is_a? def class; Proc; end def inspect; "#<Proc:0x#{object_id.to_s 16}@memoize>"; end end def memoize hsh = Hash.new {|h, k| h[k] = self[k]} hsh.__send__ :extend, ProcLike hsh end end 似乎挺完美,但是没完呢,还得盖掉 Hash 的很多东西…… 不如换个思路: class Proc module Memoized def [] x # 嗯,这样可选择性更强,用 call 不 memoize,用 [] 就 memoize @mem[x] || (@mem[x] = call x) end def invalidate x @mem.delete x end def clear_cache @mem = {} end def memoized? true end end def memoize @mem = {} self.__send__ :extend, Memoized self end def memoized? false end end |
|
返回顶楼 | |
发表时间:2009-06-10
为了通用实用嘛。像C#的话,之前看到Bart de Smet用Expression Tree来模拟memoization和currying,效果就不错。Expression Tree编译出来的delegate就跟普通的看起来一样。
P.S. s还是z其实问题不大……只是我见过的写法都是z的多。 |
|
返回顶楼 | |
发表时间:2009-06-10
RednaxelaFX 写道 为了通用实用嘛。像C#的话,之前看到Bart de Smet用Expression Tree来模拟memoization和currying,效果就不错。Expression Tree编译出来的delegate就跟普通的看起来一样。
P.S. s还是z其实问题不大……只是我见过的写法都是z的多。 嗯…… 如果 s 用多了,也就成了通假字 …… |
|
返回顶楼 | |
发表时间:2009-06-29
class Proc module Memoized def [] x, *arg # 嗯,这样可选择性更强,用 call 不 memoize,用 [] 就 memoize yy = arg.length == 0 ? x : [x, arg].flatten @mem[sol_arg(x, arg)] || (@mem[sol_arg(x, arg)] = call x, arg) end def invalidate x, *arg @mem.delete sol_arg(x, arg) end def clear_cache @mem = {} end def memoized? true end private def sol_arg x, arg arg.length == 0 ? x : [x, arg].flatten end end def memoize @mem = {} self.__send__ :extend, Memoized self end def memoized? false end end 借楼主思路继续改进以支持多参(多参的情况还是占多数)。 |
|
返回顶楼 | |