【问题标题】:How can I return nil if a key does not exist in OpenStruct?如果 OpenStruct 中不存在密钥,如何返回 nil?
【发布时间】:2015-10-27 22:31:02
【问题描述】:

我有一个传递给OpenStruct 的哈希值,以便使用. 使其成为单词。这完美地工作。但是,当我尝试访问不存在的密钥时,undefined method <unknown key> for #<Hash:0x7f24ea884210> (NoMethodError) 会被提出。我怎样才能让它返回nil

如果我使用原始哈希尝试相同的操作,我会得到nil,但不会使用OpenStruct!!

程序中的sn-p:

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?

【问题讨论】:

  • 你能展示你目前拥有的东西吗?
  • @squiguy 我添加了一个小sn-p。看看是否正常
  • 如何让它返回 nil? 通过捕获代码中的错误并返回 nil。 OpenStruct 不会返回 nil,无论你多么想要它。 如果我用原始哈希尝试同样的事情,我会得到 nil,但使用 OpenStruct 不会!! 你理解 OpenStruct 是一个哈希吗?因为不是。仅仅因为一个类有一个实例变量是一个 Hash 并不意味着该类是一个 Hash。
  • 好的,我明白你的意思,但如果我将TXT 发送到其他程序。当我尝试访问其中的值时,我会发现这个错误!!?我想避免这种情况。有没有办法覆盖 OpenStruct 的 getter 函数??

标签: ruby nomethoderror


【解决方案1】:

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

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

require 'recursive-open-struct'

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

【讨论】:

    【解决方案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. ''
    

    【讨论】:

    • 正确。制作一种递归生成哈希的方法OpenStructs 也是我会做的。不需要对OpenStruct、外部库或乱七八糟的救援进行任何修改。
    • @wspurgin 现在关于OpenStruct 的一些事情对我来说很有意义。它有我可以覆盖的getitem 函数吗?假设如果我打印 TXT 它会显示一个大的 openstruct 对象,但我想将它显示为一个哈希!!有可能吗?
    • @AnimeshPandey 对于您的第一个问题,是和否。它实现了[] 运算符,但出于您的目的,您不想弄乱它。 Reading the source 可能看起来很吓人,但你可以从中学到很多东西。要回答您的第二个问题,如果“显示”是指irb 或控制台中的输出,那么是的,您可以通过修改inspect 函数来更改它的输出方式。 This is how they currently do it in 2.2.3
    • @AnimeshPandey 但我想补充一点,你为什么关心它的外观?这就像在说“我有这只狗,我想表现得像只鸡,但仍然看起来像条狗”。如果你想让它看起来像一只狗,那就让它变成一只狗。如果你想让它像鸡一样表现,那就让它变成鸡。 如果你想要两者让你的自己的“chickdog”并且停止试图让狗成为鸡或让鸡成为狗。简而言之,编写你自己的类来做你想要的特定的事情,并且不要强制内置的通用 为您准备的课程。
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2022-01-05
      • 1970-01-01
      • 2017-05-25
      • 2023-01-19
      • 2017-05-19
      • 2021-11-19
      • 2017-06-22
      • 2014-02-24
      • 1970-01-01
      相关资源
      最近更新 更多