如果OpenStruct中不存在密钥,我该如何返回nil?

时间:2015-10-27 22:31:02

标签: ruby nomethoderror

我有一个传递给OpenStruct的哈希值,以便用.来表达它。这非常有效。但是,当我尝试访问不存在的密钥时undefined method <unknown key> for #<Hash:0x7f24ea884210> (NoMethodError)被引发。如何让它返回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?

3 个答案:

答案 0 :(得分:2)

OpenStruct不是递归的。在这种情况下,TXT.ftp返回Hash,而不是OpenStruct,因此未定义#lastname

如果需要,可以使用名为recursive-open-struct的库。像这样使用它:

require 'recursive-open-struct'

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

答案 1 :(得分:2)

@Shel给出的答案将是最好,最简单和最干净的。

  

注意:
  如果您不想要不必要的库,那么还有另一种解决方法可以实现   是的,OpenStruct不是递归的,但我们可以创建自己的递归方法。

# 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 

此外,如果您希望对象不返回异常,那么也有一些解决方法。

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
  

注意:
  据我所知,try方法只能在Rails应用内IRBruby应用中使用。

     

我会使用:rescue方法
  警告:此方法捕获异常并做出相应响应;如果您需要以不同方式响应异常,请不要使用此选项。我希望你理解

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

答案 2 :(得分:0)

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

require 'hashie'

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