如果 OpenStruct 中不存在键,我如何 return nil?

How can I return nil if a key does not exist in OpenStruct?

我有一个散列值传递给 OpenStruct 以使其与 . 成词。这非常有效。但是每当我尝试访问一个不存在的密钥时 undefined method <unknown key> for #<Hash:0x7f24ea884210> (NoMethodError) 就会被引发。我怎样才能做到 return nil?

如果我用原始哈希尝试同样的事情,我会得到 nil 但不会用 OpenStruct!!

程序片段:

TXT_HASH = load_data("test.txt")
pp TXT_HASH[:ftp][:lastname]  ## print nil as lastname does not exist

TXT = OpenStruct.new(TXT_HASH)
pp TXT.ftp.lastname  ## raises NoMethodError ## Can it return nil?

OpenStruct 不是递归的。在这种情况下 TXT.ftp returns 是一个 Hash,而不是 OpenStruct,所以 #lastname 没有定义。

如果需要,有一个库叫做 recursive-open-struct。像这样使用它:

require 'recursive-open-struct'

TXT = RecursiveOpenStruct.new(TXT_HASH)
pp TXT.ftp.lastname #=> nil

然而@Shel给出的答案是最好的,简单明了。

Note:
If you do not want to require unnecessary library then there is another workaround to implement.
Yes OpenStruct is not recursive yet we can create our own recursive method to do so.

# This method is kind of factory to create OpenStruct instances
def get_recursive_ostruct(object)
  if object.is_a?(Hash) 
    object = object.clone
    object.each do |key, value|
      object[key] = get_recursive_ostruct(value)
    end
    OpenStruct.new(object)
  else
    object
  end
end

并使用此方法

require 'ostruct'

hash = {first: 'this is first', second: {first: 'first of second', second: 'second of second'}}

obj = get_recursive_ostruct(hash)
#=>  #<OpenStruct first="this is first", second=#<OpenStruct first="first of second", second="second of second">> 

obj.second.second
#=> "second of second" 

obj.second.third
#=> nil 

此外,如果您不想 return 异常,那么还有一些解决方法。

TXT.ftp.lastname  ## raises NoMethodError 
TXT.ftp.try(:lastname)  ## returns nil if `lastname` is not available

TXT.try(:ftp).try(:lastname)  ## returns nil even if `ftp` is not available

Note:
As far as I know, try method is only available inside Rails app not in IRB or ruby apps.

I would use: rescue method
Caution: this method catches exceptions and responds accordingly; Don't use this if you need to respond to exceptions differently. I hope you understand

TXT.ftp.lastname rescue nil # respond with default value i.e. nil
TXT.ftp.lastname rescue '' # respond with default value i.e. ''

如果你想要一个递归的 OpenStruct,另一种选择是使用 Mash from the hashie gem:

require 'hashie'

text = Hashie::Mash.new(text_hash)
p text.ftp.lastname #=> nil