0

マークした行の周りで問題を引き起こしている次のコードがあります。

arr = 'I wish I may I wish I might'.split

dictionary = Hash.new

arr.each_with_index do |word, index|
  break if arr[index + 2] == nil

  key = word << " " << arr[index + 1] #This is the problem line 
  value = arr[index + 2]

  dictionary.merge!( { key => value } ) { |key, v1, v2| [v1] << v2 }
end
puts dictionary

このコードを実行すると、次の出力が期待されます。

{"I wish"=>["I", "I"], "wish I"=>["may", "might"], "I may"=>"I", "may I"=>"wish"}

ただし、代わりに得られるのは

{"I wish"=>["I may", "I"], "wish I"=>["may I", "might"], "I may"=>"I wish", "may I"=>"wish I"}

問題の行を次のように置き換えると、

key = word + " " + arr[index + 1]

すべてが期待どおりに機能します。予期しない動作を引き起こした私の回線の最初のバージョンについてはどうですか?

4

2 に答える 2

1

String#<<メソッドは、呼び出された元のオブジェクトを変更します。これは、配列word内の文字列の 1 つへの単なる別の参照である変数によって参照されるオブジェクトです。arrこの効果は、次のコードで確認できます。

 a = 'Hello'
 b = a << ' ' << 'World'
 puts a.__id__
 puts b.__id__

したがって、イテレータを介した 1 つのパスでそのメソッドを使用すると、次のパスにも影響します。

一方、String#+メソッドは、結合された文字列を保持する新しい String オブジェクトを作成します。この方法では、反復子を 1 回通過しても他のパスには影響しません。

于 2013-08-09T15:50:38.763 に答える