Ruby Hash为我知道存在的密钥返回nil值

时间:2017-01-20 00:07:25

标签: ruby hash

我疯狂地试图解决哈希中的简单哈希上的键/值问题。

我的密钥是" OpenStudio :: OptionalString"它来自我的代码中使用的API:

#---NOTE---: key here is of type OpenStudio::OptionalString

my_hash[key]['heating_plant_system'] = 'Boiler' 
my_value = my_hash[key]['heating_plant_system'] #returning nil

在调试模式下,我检查了哈希并看到第一行正确输入了键/值输入,但是当我运行第二行时,我无法检索该值。 my_value将返回零。我知道这是由于这种奇怪的密钥类型,但我无权改变它。

尝试从哈希中访问此值时,我是否犯了一个愚蠢的错误?

为了保持一般性,我可能牺牲了太多的背景。这是一个完整的例子:

require 'openstudio'

model = OpenStudio::Model::Model.new
my_zone = OpenStudio::Model::ThermalZone.new(model)

my_zone.setName('Zone 1')

zone_hash = Hash.new { |h, k| h[k] = { } }

zone_hash[my_zone.name]['heating_plant'] = 'Boiler'

puts "my zone's name is #{my_zone.name}" #Output: 'my zone's name is Zone 1'
puts zone_hash.to_s #Output: {#<OpenStudio::OptionalString:0x5fa4980 @__swigtype__="_p_boost__optionalT_std__string_t">=>{"heating_plant"=>"Boiler"}}

if zone_hash[my_zone.name]['heating_plant'].nil?
  puts 'Im unable to access this hash, help!' #<--- this is executed
else
  puts "I am able to access #{zone_hash[my_zone.name]['heating_plant']}"
end

由于我不能(轻松)撤消这个zone_hash在我的实际代码库中如何工作,方法是将键更改为OpenStudio :: OptionalString以外的其他东西,我使用此循环作为解决方法。它并不漂亮,但它完成了我需要做的小检查的工作:

zones_hash.each {|k,v|
   if zone.name.to_s == k.to_s
     v.each {|k1,v1|
       if k1 == 'heating_plant'
         heating_plant = v1.to_s
       end
     }
   end
 }

2 个答案:

答案 0 :(得分:4)

Ruby使用hasheql?来检查哈希键的相等性。

看起来OpenStudio::OptionalString可能无法正确实现这些。如果是这种情况,您的最佳解决方案是使用另一个密钥。

Ruby对散列键做出以下假设 - 如果要将两个对象视为相同的键,则它们必须返回相同的hash值,但是具有相同的散列值并不意味着它们是相同的键。方法eql?在内部用于解决这些问题。

您还可以修复hash类上的eql?OpenStudio::OptionalString方法,但也许该库在内部依赖于“损坏”行为。这就是为什么我建议只使用另一个哈希键,例如这些对象的字符串表示。

答案 1 :(得分:-1)

只要对象是唯一的,哈希键就可以是任何对象类型。唯一性或相等性的定义可在“Hash Keys”中找到。

默想:

v1 = %w(a b)
v2 = %w(c d)
hash = {v1 => 1, v2 => 2}
hash # => {["a", "b"]=>1, ["c", "d"]=>2}
hash[v1] # => 1
hash[%w(a b)] # => 1

只要密钥是唯一的,您就可以使用它:

class Foo
end

foo1 = Foo.new
foo2 = Foo.new

foo1.hash # => 1202274030892197226
foo2.hash # => 2774925608615277787

hash = {foo1 => 1, foo2 => 2}
hash[foo1] # => 1

甚至:

class Foo
  def initialize
    @init_time = Time.now
  end

  def init_time
    @init_time
  end
end

foo1 = Foo.new
foo2 = Foo.new

foo1.init_time.to_f # => 1484874655.324574
foo2.init_time.to_f # => 1484874655.324577

hash = {foo1.init_time => 1, foo2.init_time => 2}
hash[foo1.init_time] # => 1
  

不完全正确,Ruby使用hash和eql?对于哈希等式,它恰好是默认实现依赖于object_id

你是对的,已经有很长一段时间了,因为我很清楚为什么它们是独一无二的。来自the docs

  

当两个对象的hash值相同且两个对象彼此为eql?时,它们引用相同的哈希键。