新手问题 ruby 中循环的理解

vianvio · 2014年05月21日 · 最后由 vianvio 回复于 2014年05月21日 · 3459 次阅读

新人刚接触 ruby 半个月,在啃英文原版书。 看了 ruby 中各种颠覆以往概念的循环后,有一点见解想确认一下,顺便加深一些对 ruby 的理解。

在其他语言中往往是在需要遍历的时候采取当即使用循环。 而 ruby 中 blocks 的存在,是否变成在设计初期,就站在一个高度上考虑全局循环的可能。 换句话说,在设计对象时将核心的循环设计在基础方法里,后面的业务功能只是在反复调用这个核心循环。 也就是说其他语言中一个系统可能有几百行 for(),而在 ruby 里虽然有几百次循环,而实际相当于 for() 的,只有 1 处?

表达的可能有点奇怪,还请见谅。

不。Ruby 开始设计使用 block 并没有用到延迟迭代,这个好像到了 2.0 才引入。 这个设计初衷应该是向函数式靠拢:程序员不必关注如何迭代,而是如何处理逻辑(循环体)。

2.0 引入了 Enumerable::Lazy ,让链式的迭代处理延延后。(PS: Ruby 的迭代都是基于 each 方法的)

a = [1,2,3,4,2,5].lazy.map { |x| x * 10 }.select { |x| x > 30 } #=> 虽然同时出现 map和select,但each 一次也不会执行,程序返回迭代器
a.to_a #=> [40, 50], #=> 这里才开始执行代码,而且只执行一次 each

这里是详细讲解了 Enumerable::Lazy,有兴趣的话可以看一下:http://railsware.com/blog/2012/03/13/ruby-2-0-enumerablelazy

#1 楼 @saiga 感谢,受教了。可是对于 each 方法本身而言,是在数组对象中的,也就是无论在逻辑中使用多少次 map/ select,最终通过数组中的 each 方法来完成迭代的,对吗? 如果这样理解没错的话,是不是 ruby 的对象设计一般都会在对象自身方法里写一个底层的类似 each 的方法,用来提供后续所有逻辑处理使用?(或者 object 类本身已包含 each?还没看过底层抱歉)

#3 楼 @vianvio 大多都使用数组和 hash 吧。都有 each。each 就是简单的循环。

Enumerable#each 只要 mixin Enumerable 并实现 each 方法,就可以免费得到其余的 22 个方法。

Implementing Enumerable: Write One Method, Get 22 Free

class MultiArray
      include Enumerable

      def initialize(*arrays)
        @arrays = arrays
      end

      def each
        @arrays.each { |a| a.each { |x| yield x } }
      end
    end

    ma = MultiArray.new([1, 2], [3], [4])
    ma.collect                                        # => [1, 2, 3, 4]
    ma.detect { |x| x > 3 }                        # => 4
    ma.map { |x| x ** 2 }                             # => [1, 4, 9, 16]
    ma.each_with_index { |x, i| puts "Element #{i} is #{x}" }
    # Element 0 is 1
    # Element 1 is 2
    # Element 2 is 3
    # Element 3 is 4

#4 楼 @chenge 哦。我傻了,哈哈。不过后续还是有问题。和一开始问的循环理念类似,由于 block 的存在,是否有必要在所有类的基础方法中,都添加 block?这样的话是否会有极大的延展性?是否有负面影响?

#5 楼 @saiga 太感谢了,这个例子也很赞!

需要 登录 后方可回复, 如果你还没有账号请 注册新账号