次のRubyコードに遭遇しました:
class MyClass
attr_accessor :items
...
def each
@items.each{|item| yield item}
end
...
end
each
メソッドは何をしますか?特に、yield
が何をするのかわかりません。
これは、サンプルコードを具体化する例です。
_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
_レシーバーを繰り返し処理し、最後のアイテムに到達すると停止し、エラーを回避して、物事をきれいに保ちます。
ブロックを受け取るメソッドを作成するときは、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
コードブロックを受け取るRubyメソッドは、yield
キーワードを使用して呼び出すことで呼び出します。リストを反復処理するために使用できますが、あなたのような反復子ではありません。他のいくつかの他の言語で見つけてください。
ここ は、私がこれまでにできたよりもうまく説明できる良い説明です。
私の理解によれば、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
が出力されます。
読み込み中
ゲームが読み込まれました
yield
は、メソッドに渡されたブロックを呼び出して引数を与えるようにRubyに指示します。
yield
ステートメントがエラーを生成しないのに対して、メソッドがブロックで呼び出されなかった場合、return
はエラーを生成します。
return
は単一の値のみを送信できますが、Yield
は巨大な値のオブジェクトを返します。
正味の効果は、MyClassのインスタンスで.eachを呼び出すことは、そのインスタンスの.itemsで.eachを呼び出すことと同じであるということです。
初心者として、私がアビの答えにぶつかるまで、多くの答えを見ると私は混乱しました。
yieldコマンドは、メソッド内のコードの実行を一時停止し、代わりに、それを呼び出したコードのブロックに制御を戻し、そのコードを実行し、その後、メソッドの残りの部分の実行を続行します。これが私にとってそれを明確にした例です:
def hello
puts "hello"
yield
puts "world"
end
hello do
puts "there"
end
出力:
こんにちは
そこ
世界
Cpmが言ったように、ブロックを取得して実行します
簡単な例:
def my_method
yield
end
my_method do
puts "Testing yield"
end
Testing yield
=> nil