web-dev-qa-db-ja.com

「yield」キーワードはRubyで何をしますか?

次のRubyコードに遭遇しました:

class MyClass
    attr_accessor :items
    ...
    def each
        @items.each{|item| yield item}
    end
    ...
end

eachメソッドは何をしますか?特に、yieldが何をするのかわかりません。

32
Misha Moroshko

これは、サンプルコードを具体化する例です。

_class MyClass
  attr_accessor :items

  def initialize(ary=[])
    @items = ary
  end

  def each
    @items.each do |item| 
      yield item
    end
  end
end

my_class = MyClass.new(%w[a b c d])
my_class.each do |y|
  puts y
end
# >> a
# >> b
# >> c
# >> d
_

eachはコレクションをループします。この場合、_@items_配列の各項目をループし、new(%w[a b c d])ステートメントを実行したときに初期化/作成されます。

_yield item_メソッドの_MyClass.each_は、itemを_my_class.each_に接続されたブロックに渡します。生成されるitemは、ローカルのyに割り当てられます。

それは役に立ちますか?

さて、ここでeachがどのように機能するかについてもう少し説明します。同じクラス定義を使用して、ここにいくつかのコードがあります:

_my_class = MyClass.new(%w[a b c d])

# This points to the `each` Enumerator/method of the @items array in your instance via
#  the accessor you defined, not the method "each" you've defined.
my_class_iterator = my_class.items.each # => #<Enumerator: ["a", "b", "c", "d"]:each>

# get the next item on the array
my_class_iterator.next # => "a"

# get the next item on the array
my_class_iterator.next # => "b"

# get the next item on the array
my_class_iterator.next # => "c"

# get the next item on the array
my_class_iterator.next # => "d"

# get the next item on the array
my_class_iterator.next # => 
# ~> -:21:in `next': iteration reached an end (StopIteration)
# ~>    from -:21:in `<main>'
_

最後のnextで、イテレータが配列の最後から外れたことに注意してください。これは、[〜#〜] not [〜#〜]ブロックを使用する場合の潜在的な落とし穴です。配列内の要素の数がわからない場合は、あまりにも多くのアイテムを要求して取得できるためです。例外。

ブロックでeachを使用すると、_@items_レシーバーを繰り返し処理し、最後のアイテムに到達すると停止し、エラーを回避して、物事をきれいに保ちます。

31
the Tin Man

ブロックを受け取るメソッドを作成するときは、yieldキーワードを使用してブロックを実行できます。

例として、eachは次のようにArrayクラスに実装できます。

class Array
  def each
    i = 0
    while i < self.size
      yield( self[i] )
      i = i + 1
    end
  end
end

MyClass#eachブロックを取ります。インスタンスのitems配列内のアイテムごとにそのブロックを1回実行し、現在のアイテムを引数として渡します。

次のように使用できます。

instance = MyClass.new
instance.items = [1, 2, 3, 4, 5]
instance.each do |item|
  puts item
end
15
cpm

コードブロックを受け取るRubyメソッドは、yieldキーワードを使用して呼び出すことで呼び出します。リストを反復処理するために使用できますが、あなたのような反復子ではありません。他のいくつかの他の言語で見つけてください。

ここ は、私がこれまでにできたよりもうまく説明できる良い説明です。

10
Gerhard

私の理解によれば、yieldはブロックからコードを実行します。

def name
    puts "A yield will be called with id of 12"
    yield 12
    puts "A yield will be called with id of 14"
    yield 14
end


name {|i| puts "I am called by yield name #{i}"}

出力:

歩留まりは12のIDで呼び出されます

私はイールドネーム12で呼ばれています

イールドはID14で呼び出されます

イールドネーム14で呼ばれています

歩留まりはどのように機能しますか?

したがって、yieldが来るところならどこでもname関数が実行されると、ブロックコードが実行されます。これはname {|i| puts "I am called by yield name #{i}"}です

Word yield 12があり、ブロック内でコードを実行して、iの値として12を渡していることがわかります。

これがそのゲームの例です:

def load_game
    puts "Loading"

    yield

end


load_game { puts "Game loaded" }

これにより、loadingを出力した直後にgame loadedが出力されます。

読み込み中

ゲームが読み込まれました

5
Ilyas karim

yieldは、メソッドに渡されたブロックを呼び出して引数を与えるようにRubyに指示します。

yieldステートメントがエラーを生成しないのに対して、メソッドがブロックで呼び出されなかった場合、returnはエラーを生成します。

returnは単一の値のみを送信できますが、Yieldは巨大な値のオブジェクトを返します。

5
Kaleem Ullah

正味の効果は、MyClassのインスタンスで.eachを呼び出すことは、そのインスタンスの.itemsで.eachを呼び出すことと同じであるということです。

4
Karl Knechtel

初心者として、私がアビの答えにぶつかるまで、多くの答えを見ると私は混乱しました。

yieldコマンドは、メソッド内のコードの実行を一時停止し、代わりに、それを呼び出したコードのブロックに制御を戻し、そのコードを実行し、その後、メソッドの残りの部分の実行を続行します。これが私にとってそれを明確にした例です:

def hello
    puts "hello"
    yield 
    puts "world"
end

hello do
    puts "there"
end 

出力:

こんにちは

そこ

世界

4
Ryanjr

Cpmが言ったように、ブロックを取得して実行します

簡単な例:

def my_method
  yield
end


my_method do
  puts "Testing yield"
end

Testing yield
=> nil 
3
Abhi