Ruby 板


LINE

Ruby standard library 里有个 Generator, 放在 generator.rb 里。 大抵上是拿来把 internal iterator 转换成 external iterator 用的。 两种 iterator 有什麽差别?如果你熟悉 C++ 或 Java 的话, 他们所使用的就是 external iterator. 顾名思义,这是一种外部的 iterator, 即 iterator 本身跟 container/collection 是分开的。 C++: typedef std::vector<int> vint; vint v; for(vint::iterator i=v.begin(), iend=v.end(); i!=iend; ++i) std::cout << *i << "\n"; Java: Vector<Integer> v = new Vector<Integer>(); for(Iterator i=v.iterator(); i.hasNext();) out.println(i.next()); 如果是 internal iterator 的话,就像是 foreach/for in 那样 C++: BOOST_FOREACH(int i, v){ // 由於这是 macro 做的,不确定能不能省略 std::cout << i << "\n"; } Java: for(int i: v) out.println(i); 也就是说,你只能依序得到元素,但你不能操控会给你的元素是什麽。 external iterator 有比较强大的弹性,internal iterator 使用起来方便。 Ruby 的 each 很明显是 internal iterator, 你把要施行的动作传给 container/collection, 然後由他来替你施行动作。 可以看成是这样: def each func = nil, &block # 以下决定使用 block 或传入的 Proc like 物件,写入 func 中 if block_given? func = block else raise TypeError, "#{func} don't respond to :call" unless func.respond_to? :call func = func end # 以下依次呼叫外部 Proc like 物件,传入被 travel 者 0...self.size.times{|i| func.call self[i] } end 由於 travel 的动作被隐藏起来了,所以使用时方便,不用再去说明 travel 法。 缺点也正是因为 travel 被隐藏起来了,所以如果不是要用预设的 travel 法, 则动他不得。要用非预设的方式,只能使用 external iterator. Ruby 目前没什麽好的 external iterator, 所以只好使用 Generator 去模拟。 (当然,Array 很好做 external iterator, 但其他的就比较困难。) 用法大概是像这样: v = [0, 1, 2, 3, 4] g = Generator.new v while g.next? puts g.next end Generator 的做法很单纯,他还是使用 each 去呼叫,不过却去「卡住」 travel 的过程。这就是靠 Continuation 去做了。 关於 Continuation, 本板前面有其相关心得,不多重复了。 写成概念有点像这样: def next @target.each{|i| 卡住 return i } end 每次呼叫 Generator 的 next 时,就放掉「卡住」,於是传回当时的 i, 然後在传回下一个 i 之前,再卡住执行流程。next 可以用这种概念实作出来。 不过 prev 就没办法了。Generator 有提供 rewind, 使 travel 整个重来, 但是没有 prev 这种能够往前走一格的方式…。要有的话,势必不能使用 each. 幸运的是……由於 standard library 的 generator.rb 我看不懂, 看了好一阵子,只得到了点概念,但还是搞不懂他为什麽要把实作变得 这麽复杂 :( 没记错的话,总共有三个 Continuation 物件,又有一个额外的 queue array... 我完全搞不懂他这个 queue 存在的意义。 所以我自己尝试写了一下,以确保我没有误解什麽东西。我只用了两个 Continuation, 没有 queue. 当然,整个概念还是从他的程式码来的, 我只是把我看不懂的部份拿掉,然後用自己的意思解读一次。 用该档案里面的 unit test 测试了一下,每一个测试都通过了, 很搞不懂原本的实作为什麽要弄得这麽复杂…。更何况由於我撰写的 里面少了一个 Continuation 和一个 array, 执行效率应该还比较高。 不知道是不是我疏忽了什麽,不然这样的状况似乎有点诡异。 * 原本我是想详细解说我的实作的,不过 Continuation 我觉得有点复杂, 从写完到现在也经过一段时间了,详细的做法我已经不记得了…。 Orz 更何况此篇已经有点太长了,也差不多是「欲知详情,请待下回分晓」的时候 XD 所以以下就仅附上程式码,以 Ruby license 释出。 p.s. 我觉得 Continuation 太过於复杂(另类 goto),似乎应该少用为妙 class Generator include Enumerable def initialize enum = nil, &block if enum @block = lambda{|g| enum.each{|i| g.yield i}} else @block = block end @index = 0 @value = nil if @con_next = callcc{|c|c} @block.call self @con_next.call end end def next raise EOFError, "no more elements available" if end? @index += 1 result = @value @con_yield.call if @con_next = callcc{|c|c} result end def yield value @value = value @con_next.call if @con_yield = callcc{|c|c} end def next? return true if @con_yield return false end def end? !next? end def index @index end alias_method :pos, :index def current raise EOFError, "no more elements available" unless @value @value end def rewind initialize &@block self end def each rewind yield(self.next) while self.next? self end end -- In Lisp, you don't just write your program down toward the language, you also build the language up toward your program. 《Programming Bottom-Up》- Paul Graham 1993 --



※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 220.135.28.18
1F:推 poga:好文我推 03/01 22:37







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:iOS站内搜寻

TOP