2012-05-05 6 views
4
インターネット上の多くのケースでは

私は可算ためeach方法の例を見て:人はこの1つを使用していないのはなぜEnumerableのブロックリンクは許可されていますか?

def each(&block) 
    @items.each do |item| 
    block.call(item) 
    end 
end 

def each(&block) 
    @items.each(&block) 
end 

どんな違いがありますか?

+1

を(私はそう、私は答えを作成しません100%確実ではないけど、私の知る限り実際的な違いはありません最初はおそらく遅く、間違いなくもっと冗長である)。なぜ人々はそれを使用するのですか?おそらくそれは取得するのと同じくらい簡単なので、2番目のブロックはブロック/ Procsを回避する方法についていくつかの理解が必要です。 – tokland

+2

@tokland:それは完全には正しいとは言えません。ブロックが2番目のブロックと等価でなければ、最初は列挙子を返す必要があります。 –

+0

@Niklas、そうだよ、Rubyはそれぞれにブロックが渡されないときに列挙子を返すようになった。第二の理由を使用するもう一つの理由。 – tokland

答えて

4

実は私は、次のバージョンは、より一般的に見られていると思う:

def each 
    @items.each { |i| yield i } 
end 

これはあなたの最初のサンプルコードと同等です。

class Test 
    def initialize(items) 
    @items = items 
    end 

    def each1 
    @items.each { |i| yield i } 
    end 

    def each2(&block) 
    @items.each(&block) 
    end 
end 

を守ってください:このと2番目のバージョン間の微妙な違いがあります

irb(main):053:0> Test.new([1,2,3]).each2 
=> #<Enumerator: [1, 2, 3]:each> 
irb(main):054:0> Test.new([1,2,3]).each1 
LocalJumpError: no block given (yield) 
    from (irb):43:in `block in each1' 
    from (irb):43:in `each' 
    from (irb):43:in `each1' 
    from (irb):54 
    from /usr/bin/irb:12:in `<main>' 

バージョンはその代表者、何もブロックが指定されていない場合は反復可能で、実際に列挙子を返し根底にブロックされ非常にいいです。それは私たちがこのようなものを書くことができます:

irb(main):055:0> Test.new([1,2,3]).each2.map { |x| x + 1 } 
=> [2, 3, 4] 

は、私たちの明示的なバージョンで同じことを達成するために、我々はこのようにそれを適応させる必要があるだろう。でも、より詳細な

def each1 
    return enum_for(:each1) unless block_given? 
    @items.each { |i| yield i } 
end 

はどれ。ボトムライン(Bottomline):可能であれば、ブロックを基になる列挙型に委譲して、コードの重複やこれらのような微妙な問題から自分自身を守ります。

ところで、あなたのeachメソッドの2つ折りの性質を理解したので、別の名前を付けるのが理にかなっています。たとえば、あなたがString#charsIO#linesのような方法の例に従うと、あなたの方法items呼び出すことができます。

def items(&block) 
    @items.each(&block) 
end 
+0

ありがとう、あなたの3番目のコードの例は私に違いを示した:)のように、私は正しかった:) –