我有以下代码导致我在标记的行周围出现问题。
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]
一切都按预期工作。我的第一个版本导致意外行为的原因是什么?
答案 0 :(得分:1)
key = word&lt;&lt; “”&lt;&lt; arr [index + 1]
问题是String#<<执行就地操作,因此下次使用时会修改字符串。另一方面,String#+返回一个新副本。
你被一种必要的副作用所困扰(这并不罕见,因为副作用是一个巨大的错误来源。除非有非常令人信服的性能原因,functional方法会产生更好的代码)。例如,可以使用Facets中的each_cons
和map_by
来编写它:
words = 'I wish I may I wish I might'.split
dictionary = words.each_cons(3).map_by do |word1, word2, word3|
["#{word1} #{word2}", word3]
end
答案 1 :(得分:1)