【问题标题】:Rails 3.1: Ruby idiom to prevent .each from throwing exception if nil?Rails 3.1:Ruby 成语防止 .each 在 nil 时抛出异常?
【发布时间】:2012-03-24 12:31:43
【问题描述】:

有没有办法使用.each,这样它就不会在对象为 nil 或为空时引发错误(无需添加额外的 nil/blank 测试?

如果我说phonelist.each do |phone|,如果phonelist为空,那么该块不应该被执行。

但在我看来 (haml) 我有 - @myvar.phonelist.each do |phone|,如果 phonelist 为空,它会抛出 NoMethodError。

我经常遇到这种情况,并且总是通过为 .blank 添加显式检查/分支来解决?但似乎应该有一种更简单的方法来告诉 .each 空意味着什么都不做。

【问题讨论】:

  • 在一个空的枚举上调用each应该什么都不做。
  • @AndrewMarshall 但这不是正在发生的事情,他在nil 上打电话给each
  • @AndrewMarshall:他的意思是nil 对象,而不是空集合。
  • 是的。谢谢。愚蠢的虫子。辅助方法设置为 nil 而不是 []。感谢您的 cmets。
  • @jpwynn 用“SOLVED”编辑你的问题并给出解释并不是一个好主意。如果他们解决了问题,请接受其中一个答案,或者在解决方案中发布您自己的答案。

标签: ruby-on-rails ruby each


【解决方案1】:

您可以使用try 方法在nil 上调用.each,这样如果对象为nil 或空,它就不会抛出错误。

phonelist = nil
phonelist.try(:each){|i| puts i}

【讨论】:

  • 我想我不明白为什么人们会求助于这样的东西,而最好的办法是简单地确保不应该为 nil 的东西永远不会为 nil。如果无法做到(无论出于何种原因),为什么要这样做而不是简单的 if 语句?我不明白。
  • 我同意最好确保你永远不会得到 nil,但我不明白为什么添加 if 语句是比使用 try 更好的解决方案。任何一种方法都应该能胜任。
  • 我想我不认为在每种情况下都必须重复变量名更清晰或更简单(尤其是在使用长变量名的情况下),但是尝试的好处是您可以继续链接将方法放在一起,而不必用 if 将其分解。当然,这真的取决于情况。
  • 这个聪明而干净,但仍然只是一个创可贴。我同意 Ed S. 你应该对对象做一些不同的事情,以便它返回 nil 以外的东西(比如一个空数组)。
【解决方案2】:

只需执行以下操作:

Array(phonelist).each do |phone|
  #deal with your phone
end

如果 my_variable 为 nil,Array(my_variable) 将确保返回一个数组。

如果 my_variable 已经是一个数组,它不会创建一个新的数组,所以在任何你想要的地方使用它是安全和轻便的!

【讨论】:

  • 我喜欢。简洁大方
【解决方案3】:

您正试图在更大的问题上使用创可贴。

Ruby 有一个 nil 的概念;无法绕过它。如果您在 nil 上调用方法,那么您假设它是有效的,即您的 设计 假设它是有效的。所以问题真的是:你的设计中的漏洞在哪里?为什么你的假设不正确?

这里的问题不是你不能在一个不支持它的对象上调用任意方法;问题是您的数据被假定为有效,但显然并非总是如此。

但在我看来 (haml) 我有 - @myvar.phonelist.each 做 |phone|如果 phonelist 为空,则抛出 NoMethodError。

没有。如果phonelist 不是实现.each 的对象,则会引发错误。非常不同。

如果为空,您始终可以将其初始化为空数组,即phonelist ||= [],但我更喜欢尽可能确保有效数据的设计。

【讨论】:

  • 有时你无法控制从 apis 返回的数据结构。事情将是零,问题是有效的
  • 好的,那么显然你必须在这种情况下检查 null 。看不出这与这个问题有什么关系。
【解决方案4】:

不敢相信还没有人提出这个建议:

(@myvar.phonelist || []).each do |phone|
   ...

如果phonelistnileach 将在空数组上循环,执行块零次。

但是,如果 phonelist 不是可枚举的(例如数组),这仍然会引发异常。

【讨论】:

    【解决方案5】:

    如果您从散列(例如解析的 JSON 文件)中获取 phonelist,您可能希望使用 fetch[] 作为默认值。

    phonelist = my_data.fetch('phonelist', [])
    

    【讨论】:

      【解决方案6】:

      只需确保空的phonelist[],而不是nil 值。

      另外,nil 值在 Ruby 中是错误的,因此您可以使用 nil-punning

      if phonelist
         phonelist.each do |phone|
           ...
      

      【讨论】:

        猜你喜欢
        • 2018-12-23
        • 2017-09-30
        • 2022-01-01
        • 1970-01-01
        • 2022-01-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多