【问题标题】:Ruby check if nil before calling methodRuby 在调用方法之前检查是否为 nil
【发布时间】:2012-09-07 16:11:19
【问题描述】:

我在 Ruby 中有一个字符串,我在其上调用 strip 方法来删​​除前导和尾随空格。例如

s = "12345 "
s.strip

但是,如果字符串是 empty nil 我会收到以下错误。

NoMethodError: undefined method `strip' for nil:NilClass

我使用的是 Ruby 1.9,那么在调用 strip 方法之前检查值是否为 nil 的最简单方法是什么?

更新:

我在数组中的一个元素上试过这个,但遇到了同样的问题:

data[2][1][6].nil? ? data[2][1][6] : data[2][1][6].split(":")[1].strip

【问题讨论】:

  • 这个问题已经被问了几十次了:stackoverflow.com/questions/5429790/…
  • 原始发帖人注意:字符串不是您声称的空的,即s = "",它是零。它还不存在。如果它是空的,你可以检查:s.strip unless s.empty?
  • 如果字符串为空,则不会出现该错误。
  • 第二个问题,添加dig:data.dig(2, 1, 6)&.split(":")[1]&.strip。如果数据的任何部分丢失或格式错误,则整个表达式将返回 nil 而不会出错。

标签: ruby null


【解决方案1】:

Ruby 2.3.0 添加了一个安全导航运算符 (&.),它在调用方法之前检查 nil。

s&.strip

如果snil,则此表达式返回nil 而不是提升NoMethodError

【讨论】:

  • 是的——这是使 Ruby 表现得有点像一种适当的 Web 脚本语言的唯一方法。如果有一种方法可以为所有出现这种烦人且无用的行为的情况全局设置它 - 并在需要时默认将所有值“隐式转换”为字符串(如 puts 语句)。
  • 我第一次看到这个-超级有用
  • @JosephK:你用过 Ruby 吗? IO#puts 确实在其所有参数上调用 to_s,例如。 puts(5)。另外,试试class NilClass; def method_missing(*a);nil;end;end
  • 由于 Ruby 的行为不像 Ecmascript 那样,我无法计算在求和元素、放置等方面失败的次数 - 做出明智的选择 - 因为很少有“nil”的情况不应被视为“”或零(取决于上下文)。
  • @JosephK nil(或null)已被称为the worst mistake of computer science
【解决方案2】:

您可以使用 ActiveSupport(Rails 库)中的方法 try

gem install activesupport

require 'active_support/core_ext/object/try'
s.try(:strip)

或者您可以使用我的 gem tryit,它提供了额外的便利:

gem install tryit

s.try { strip }

【讨论】:

    【解决方案3】:

    如果您不介意要创建的额外对象,则可以使用以下任一方法:

    "#{s}".strip
    s.to_s.strip
    

    没有额外的对象:

    s && s.strip
    s.strip if s
    

    【讨论】:

      【解决方案4】:

      我想最简单的方法如下:

      s.strip if s
      

      【讨论】:

      • 如果你想把东西串起来就不太方便了。
      • 所需要的是一种通用的说法,“如果我在 nil 上调用一个方法,就返回 nil”,这样我们就不必用这些东西弄乱我们的代码。 IOW,我们需要“脚本语言”功能。也许在开发级别将一些东西扔到控制台中,只是为了帮助您在意外获得 nil 时进行故障排除。
      • @JosephK 查看 Jessie Sielaff 的回答。您正在寻找的内容是在 Ruby 2.3 中添加的。它被称为安全导航运算符
      • @lukad - 谢谢。现在,如果有办法让它成为默认行为。
      【解决方案5】:

      我会选择s 永远不能是nil 的解决方案。

      如果some_method 返回虚假值,您可以使用|| 运算符传递默认值:

      s = some_method || '' # default to an empty string on falsy return value
      s.strip
      

      或者,如果 s 已经分配,​​您可以使用 ||= 执行相同的操作:

      s ||= '' # set s to an empty string if s is falsy
      s.strip
      

      为缺少参数或变量提供默认方案是保持代码整洁的好方法,因为您不必将逻辑与变量检查混为一谈。

      【讨论】:

        【解决方案6】:

        适合我的方法(我知道,我不应该污染原始的Object 空间,但它非常方便,我会冒险):

        class Object
          def unless_nil(default = nil, &block)
            nil? ? default : block[self]
          end
        end
        
        p "123".unless_nil(&:length) #=> 3
        p nil.unless_nil("-", &:length) #=> "-"
        

        在您的特定情况下,它可能是:

        data[2][1][6].unless_nil { |x| x.split(":")[1].unless_nil(&:strip) }

        【讨论】:

          【解决方案7】:

          ActiveSupport 附带了一个方法:try。例如,如果 an_object 为 nil,an_object.try :strip 将返回 nil,否则将继续。语法与send 相同。参见active_support_core_extensions.html#try

          【讨论】:

            【解决方案8】:

            如果你想避免问题中出现的错误:

            s.to_s.strip
            

            【讨论】:

              【解决方案9】:

              要完成此处显示的选项,有“存在检查速记”,recommended in the Ruby Style Guide

              使用&&= 预处理可能存在或不存在的变量。使用&&= 将仅在值存在时更改值[意味着,不是nil],无需使用if 检查它的存在。

              所以在你的情况下你会这样做:

              s = "12345 "
              s &&= s.strip
              

              【讨论】:

                【解决方案10】:

                简单地说:

                s = s.nil? ? s : s.strip
                

                Tl;dr 检查 s 是否为 nil,然后返回 s,否则,剥离它。

                【讨论】:

                • @lukad 的答案比这更简单。
                • 谢谢 - 刚刚在数组中的一个元素上尝试了这个,并结合了拆分。但它似乎仍然失败:.将数据 [2][1][6].nil? ?数据[2][1][6] : 数据[2][1][6].split(":")[1].strip 。 NoMethodError: nil:NilClass 的未定义方法“strip”
                • data[2][1][6].split(":") 返回什么?好像只有一项。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-08-12
                • 1970-01-01
                相关资源
                最近更新 更多