2016-07-04 7 views
2

なぜそれがあることである:ブロックが1回だけ実行されるのはなぜですか?

array = (1..20).to_a 
array.index.each_slice(5) do |slice| 
    puts slice.inspect 
end 

リターン:

[1, 2, 3, 4, 5] 
[6, 7, 8, 9, 10] 
[11, 12, 13, 14, 15] 
[16, 17, 18, 19, 20] 

中:のみ

other_array = [] 
array = (1..20).to_a 
array.index.each_slice(5) do |slice| 
    puts slice.inspect 
    other_array.push(1) 
end 

リターン:

other_array.push(1)休憩EXをどのよう
[1, 2, 3, 4, 5] 

ブロックのエコーション?明らかな結論は、私はブロックの範囲にない変数にアクセスすることができないだろうが、それはなぜですか?

+1

実際には、ここで 'index'を呼び出す点は表示されません(原因はアレイプッシュではありません) – Vasfed

+1

文書には' '' 'index''' "ブロックも引数も与えられていないときは列挙子を返します"という理由で、私は '' '' index''を呼び出しました。 each_sliceを呼び出すためには列挙子が必要でした。今は、ArrayにModule Enumerableが含まれていることがわかり、each_sliceというメソッド自体があります。 –

+0

これを見る一つの方法は、 'enum1 = array.index#=>#<列挙子:[1、.. 20]:インデックス>; enum2 = enum1.each_slice(5)#=>#<列挙子:#<列挙子:[1、.. 20]:インデックス>:each_slice(5)> 'この戻り値を注意深く調べます。あなたは 'enum2'を"複合 "列挙子と考えることができます。 'enum2'で生成された要素は' enum2.to_a#=> [[1、... 5]、... [16、... 20]] 'のような配列に変換されています。次に、 'enum2.each {| slice | slice.inspect}#=> [1、... 5] ... [16、... 20] 'を入れます。あなたが気づいたように、 '.index'が省略されても同じ結果が得られます。 –

答えて

6

解決策がアレイドキュメントに見つかりました。私は配列の繰り返し処理をしたいと思ったときになぜ配列のindex関数を使用したのか疑問に思っていました。このためには、インデックスを呼び出さずにarray.each_sliceを使用することができます。 http://ruby-doc.org/core-2.2.0/Array.html#method-i-index

オブジェクトがobjに==であるように、進の最初のオブジェクトのインデックスを返します: インデックスは次のよう述べています。

引数の代わりにブロックが指定された場合、ブロックがtrueを返す最初のオブジェクトのインデックスを返します。一致するものが見つからない場合はnilを返します。

したがって、コードでブロックが評価され、結果がtrueであるかどうかがチェックされます。 最初の例ではputsのみを返し、nilを返します。 Nilはfalseです。それはfalse又はnilない場合
第二の例では、すべての条件がtrueあるルビーでは、単一の1
を含む配列のオブジェクトを返します。 あなたはここにこれを見ることができます:それは再び実行されませんので、それが「有効」の結果を見つけたので

if nil 
    puts "foo" 
end 
=> nil 

other_array = [1] 
if other_array 
    puts "foo" 
end 
=> "foo" 

だからあなたの第二の例ではブロックでは、偽ではない何かを返します。

戻り値として、他の戻り値が与えられていない場合は、rubyが最後の式を返します。したがって、それはother_arrayを返します。 次に、あなたは可能性があなたのコードを再フォーマットしたくない場合は、次の

other_array = [] 
array = (1..20).to_a 
array.index.each_slice(5) do |slice| 
    puts slice.inspect 
    other_array.push(1) 
    nil 
end 

これはnilを返すようにブロックを強制し、反復は動作します。

+0

これはバグによく似ています。ブロックは 'each_slice(5)'に関連付けられているので、 'index'呼び出しの動作に影響を与えるべきではありません。さらに、ブロックが 'index'呼び出しにバインドされている場合、最初の要素である' 1'を返し、 '1'で' each_slice'を呼び出すとエラーになります。 –

+0

ああ、そうです。私はそれを見ませんでした。 'index.each_slice'が実際に動作しているのは異常です。これを行うには、indexが配列を返さなければなりません。 – 0xAffe

+1

文書では、 '' '' 'index'''はブロックや引数が与えられていないときに列挙子を返します。 each_sliceを呼び出すためには列挙子が必要でした。今は、ArrayにModule Enumerableが含まれていることがわかり、each_sliceというメソッド自体があります。 –

2

それは一見トリッキーようだが、あなたは Array#index のためのドキュメントをチェックする場合には、ブロックが与えられていない場合は、この方法はEnumを返すことがわかります。最初のケースで

次に、あなたはブロックとそのEnumオブジェクトに#each_slice(n)を呼び出す

do |slice| 
    puts slice.inspect 
end 

それは#index方法にnil各時刻を返します。あなたが二番目にarray.index.each_slice(5) { nil }または

を呼び出す場合は、同じ結果を得るでしょう:このブロックの

do |slice| 
    puts slice.inspect 
    other_array.push(1) 
end 

値は、ブロック内で評価され、#index方法に[1]を返すので、それは最初のスライスを返す取得します配列のあなたが電話しても同じ結果が出るarray.index.each_slice(5) { any_non_falsy_object }

関連する問題