2017-08-22 41 views
5

`try`和`&.`(安全导航运营商)之间的区别就在这里是我的代码:是什么在Ruby中

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一条捷径,但我想我错了。有人可能会指出我正确的方向吗?

我觉得它不是红宝石相关的。葡萄也许?虽然我不明白这是怎么回事。

+0

他们是不一样的,你可以阅读更多关于区别[这里](http://mitrev.net/ruby/2015/11/13 /所述运营商合红宝石/) – Redithion

回答

9

&.#try!那样工作,而不是#try

这里是#try!(从documentation)说明:

同#try,但将引发NoMethodError异常,如果接收不为零,并且不实施的尝试方法。

所以基本上它可以免去调用nil上的方法,但是如果提供了一个对象,它将尝试像往常一样调用它的方法。

引用来自Rails文档,所以重要的是要强调 Ruby不提供#try,它是Rails,或者更精确的ActiveSupport。虽然安全导航运算符&.是Ruby 2.3.0中提供的语言功能。

6

try方法忽略了很多事情,它只是给它一个镜头,如果事情没有解决,它会被称为一天。

&条件导航选项将只有块调用nil对象。其他任何事情都被认为是有效的,并将继续发生全部后果,包括例外。

3

我到达晚会有点晚,其他答案已经介绍了它是如何工作的,但我想补充一些其他答案没有涉及的东西。

你的问题要求try&.红宝石有什么区别。 Ruby是这里的关键词。

最大的区别是try在Ruby中不存在,它是由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。

1

在评论

航行安全操作(&与@Redithion同意。)在Ruby中

方案

假设你有一个具有owneraccount,并且希望得到业主的address。如果你想成为安全,而不是风险无差错,你会写像下面这样:

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

这是非常啰嗦和恼人的输入。的ActiveSupport包括具有类似的行为(但稍后将讨论一些关键的差异)的try方法:

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

它完成同样的事情 - 如果沿着链一定的价值是它要么返回地址或nilnil。例如,如果owner设置为false,则第一个示例也可能返回false。

使用&。

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

account&.owner&.address 

更多的例子

我们来比较一下更详细的三种方法。

account = Account.new(owner: nil) # account without an owner 

account.owner.address 
# => NoMethodError: undefined method `address' for nil:NilClass 

account && account.owner && account.owner.address 
# => nil 

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

account&.owner&.address 
# => nil 

到目前为止没有意外。如果ownerfalse(在令人兴奋的低劣代码世界中不太可能,但不是不可能)?

account = Account.new(owner: false) 

account.owner.address 
# => NoMethodError: undefined method `address' for false:FalseClass ` 

account && account.owner && account.owner.address 
# => false 

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

account&.owner&.address 
# => undefined method `address' for false:FalseClass` 

这里谈到的第一个惊喜 - &.语法只跳过nil但承认假的!它不完全等同于s1 && s1.s2 && s1.s2.s3语法。

如果店主在场,但不回应address

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

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

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

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

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

下面的例子是混乱和nil&.nil?应该返回true

使用&.操作符并检查nil值时要小心。请看下面的例子:

nil.nil? 
# => true 

nil?.nil? 
# => false 

nil&.nil? 
# => nil 

参考:here