TypeError:无法将String转换为Integer

时间:2010-03-21 09:42:29

标签: ruby

我有代码:

class Scene
  def initialize(number)
    @number = number
  end
  attr_reader :number
end

scenes = [Scene.new("one"), Scene.new("one"), Scene.new("two"), Scene.new("one")]

groups = scenes.inject({}) do |new_hash, scene|
   new_hash[scene.number] = [] if new_hash[scene.number].nil?
   new_hash[scene.number] << scene
end

当我发动它时,我得到错误:

freq.rb:11:in `[]': can't convert String into Integer (TypeError)
       from freq.rb:11:in `block in <main>'
       from freq.rb:10:in `each'
       from freq.rb:10:in `inject'
       from freq.rb:10:in `<main>'

如果我将场景改为:

scenes = [Scene.new(1), Scene.new(1), Scene.new(2), Scene.new(1)]
问题消失了。

为什么我在第一种情况下收到错误消息?为什么Ruby决定将scene.number从String转换为Integer?

还有一个关于'注入'方法的问题。当Ruby初始化'new_hash'变量时,Ruby如何知道这个变量的类型?

5 个答案:

答案 0 :(得分:10)

尝试:

groups = scenes.inject({}) do |new_hash, scene|
   new_hash[scene.number] = [] if new_hash[scene.number].nil?
   new_hash[scene.number] << scene
   new_hash
end

Ruby将传递给inject()的空哈希值设置为new_hash。当块结束时,返回值用于在下一次初始化new_hash,即new_hash继续累积块的结果。

在你的原始代码中,你没有返回哈希值,但是一个数组(new_hash [scene.number]是一个数组)并且下一个循环通过Ruby抱怨,因为new_hash [scene.number]试图对数组进行查找带有字符串值,因此出现错误。

答案 1 :(得分:6)

Z.E.D.是的。有关inject的详细解释,请参阅Jay Fields' Thoughts: Ruby: inject

如图所示,您的块返回一个数组。因此new_hash中的|new_hash, scene|最终成为该数组。当Ruby尝试查找数组索引'one'时,它会抛出错误,因为'one'是String而不是Integer。

您需要做的就是返回new_hash作为Z.E.D.显示,你会得到这样的东西:

{
  "two" => [
    #<Scene:0x101836470 @number="two">
  ],
  "one" => [
    #<Scene:0x101836510 @number="one">,
    #<Scene:0x1018364c0 @number="one">,
    #<Scene:0x101836420 @number="one">
  ]
}

答案 2 :(得分:2)

为什么不使用group_by,这可能正是你想要实现的目标?

groups = scenes.group_by(&:number)
# => {"two"=>[#<Scene:0xb728ade0 @number="two">],
#     "one"=>
#       [#<Scene:0xb728ae30 @number="one">,
#        #<Scene:0xb728ae08 @number="one">,
#        #<Scene:0xb728ada4 @number="one">]}

inject是折叠操作,并不完全符合您的要求。至少以这种方式使用是很麻烦的。如果您想在合并或分组期间应用某种算法,那么带有块的merge可能是合适的。

答案 3 :(得分:0)

另外,要解释'Ruby如何知道此变量的类型'以及它为什么尝试'将String转换为整数',您可能需要修改:Ruby variables and dynamic typing

答案 4 :(得分:0)

我知道这个问题已经接受了答案,但我不禁发表答案。

groups = scenes.inject({}) { |nh, s| nh.tap {|h| (h[s.number] ||= []) << s } }