Ruby中的`try`和`& .`(安全导航操作符)有什么区别

时间:2017-08-22 19:18:04

标签: ruby-on-rails ruby if-statement nomethoderror grape-api

这是我的代码:

class Order < Grape::Entity
  expose :id { |order, options| order.id.obfuscate }
  expose :time_left_to_review do |order, options|
    byebug
    order&.time_left_to_review # ERROR
  end
  expose :created_at { |order, options| order.last_transition.created_at }
end

# NoMethodError Exception: undefined method `time_left_to_review' for #<Order:0x007f83b9efc970>

我认为&..try的捷径,但我想我错了。可能有人指出我正确的方向,我错过了什么?

我觉得这不是红宝石相关的。葡萄可能吗?虽然我不知道它是怎么回事。

5 个答案:

答案 0 :(得分:34)

&.的作用类似于#try!,而不是#try

以下是#try!(来自documentation)的说明:

  

与#try相同,但如果接收不是nil并且没有实现尝试过的方法,则会引发NoMethodError异常。

所以基本上它可以让你免于调用nil上的方法,但是如果出现一个对象,它会像往常一样调用它的方法。

引用来自Rails文档,因此重要的是要强调 Ruby没有提供#try;它由Rails提供,或者更准确地说是ActiveSupport。然而,safe navigation operator&.)是Ruby 2.3.0中提供的语言功能。

答案 1 :(得分:10)

try方法忽略了很多东西,它只是给它一个镜头,并且如果事情不能解决,就把它称为一天。

&条件导航选项阻止对nil个对象的调用。其他任何内容都被视为有效,并将继续产生全部后果,包括例外情况。

答案 2 :(得分:3)

我到这里来的时候有点晚了,其他的答案已经涵盖了它的运作方式,但是我想补充其他答案没有涉及的内容。

您的问题询问 Ruby try&.之间的区别是什么。 Ruby是这里的关键词。

最大的区别是try在Ruby中不存在,它是Rails提供的方法。如果你在rails控制台中做了类似的事情,你可以看到这个或你自己:

[1, 2, 3].try(:join, '-')
#=> "1-2-3" 

但是如果你在irb控制台中做同样的事情,你会得到:

[1, 2, 3].try(:join, '-')
NoMethodError: undefined method `try' for [1, 2, 3]:Array

&.是Ruby标准库的一部分,因此可用于任何Ruby项目,而不仅仅是Rails。

答案 3 :(得分:1)

在评论部分同意@Redithion

  

Ruby中的安全导航运算符(&。)

如果在nil对象上调用方法,则安全导航运算符将返回nil。在此之前,如果在nil对象上调用方法,则会引发如下错误。

$ nil.some_method
=> NoMethodError: undefined method 'some_method' for nil:NilClass

我们为什么需要安全导航?

很多时候,由于一些错误的输入值,我们没有得到对象。在这种情况下,如果我们继续调用具有对象的期望方法,那么如果对象变成nil对象,代码可能会中断。

为避免这种情况,引入了安全导航。这样可以确保即使调用该方法的对象为nil对象,我们的代码也不会中断。当我们很好地在方法调用失败时接收nil对象时,应使用此方法。

示例

假设您有一个拥有所有者的帐户,并且想要获取所有者的地址。如果您想安全起见并且不冒Nil错误的危险,则可以编写以下内容。

if account && account.owner && account.owner.address 
... 
end

这真的很冗长而且令人讨厌。 ActiveSupport包含try方法,该方法具有类似的行为(但有一些主要区别,稍后将讨论):

if account.try(:owner).try(:address)
...
end

它完成相同的事情-如果链中的某个值为nil,则返回地址或为nil。如果例如所有者设置为false,则第一个示例也可能返回false。

使用&。

我们可以使用安全导航操作符重写前面的示例:

account&.owner&.address

答案 4 :(得分:1)

除了上述答案之外,我还添加了一些示例。1

account = Account.new(owner: Object.new)

account.try(:owner).try(:address)
# => nil

account&.owner&.address
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>`

account.try!(:owner).try!(:address)
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>`

正如我们所见,try 不会检查接收者是否响应给定的方法。而 try!&. 的行为相同。如果接收者响应 address 方法,它们都会返回相同的结果。我更喜欢使用 &.,因为它看起来更干净。

有关安全导航操作符 (&.) 的更多信息,我发现此博客非常有用https://mitrev.net/ruby/2015/11/13/the-operator-in-ruby/