答案 0 :(得分:56)
&.
通常比try(...)
根据具体情况,这可以使您的代码更具可读性。
&.
是标准的Ruby,而不是try
方法try
未在Ruby核心库中定义,而是在Rails库中定义。当您没有开发RoR Web应用程序但是正在编写例如小助手脚本,这将相当快速。
(例如,我更喜欢Ruby而不是Bash。)
&.
使调试更容易如果调用不存在的方法,则安全遍历运算符将抛出错误。
>> "s"&.glubsch
NoMethodError: undefined method `glubsch' for "s":String
仅在nil
上,它会表现得很宽松:
>> nil&.glubsch
=> nil
try
方法将始终返回nil
。
>> "s".try(:glubsch)
=> nil
请注意,最新版本的Ruby和Rails就是这种情况。
现在假设存在名为glubsch
的方法的场景。然后你决定重命名该方法但忘记在一个地方重命名它。 (遗憾的是,红宝石会发生这种情况......)使用安全遍历操作符,您几乎会立即注意到错误(只要第一次执行该行代码)。然而,try
方法很乐意为您提供nil
,并且您将在程序执行的下游某处获得nil
相关错误。找出这样的nil
来自哪里可能很难。
使用&.
快速而艰难地进行调试比使用nil
轻快返回try
更容易调试。
编辑: 在这方面,还有try!
(有一个爆炸)的变体与&.
的行为相同。如果您不喜欢&.
,请使用它。
那会很奇怪。由于这将是一种意想不到的编程方式,请明确说明。例如,通过使用respond_to?
充实两个案例(已实现或未实现)并将其分支。
try
的阻止形式怎么样?可以将块传递给try
,而不是方法名称。该块将在接收器的上下文中执行;并且在该区块内没有适用宽大处理。因此,只需一次方法调用,它的行为与&.
相同。
>> "s".try{ glubsch }
NameError: undefined local variable or method `glubsch' for "s":String
对于更复杂的计算,您可能更喜欢这种块形式而不是引入大量局部变量。例如。
的链条foo.try{ glubsch.blam }.try{ bar }.to_s
允许foo
为nil
,但需要foo.glubsch
才能返回非nil
值。然后,您可以使用安全遍历运算符以更简洁的方式执行相同的操作:
foo&.glubsch.blam&.bar.to_s
使用try
的块形式进行复杂的计算恕我直言,因为它会妨碍可读性。当您需要实现复杂逻辑时,引入具有描述性名称的局部变量,并使用if
来分支nil
个案例。您的代码将更易于维护。
HTH!
答案 1 :(得分:20)
安全导航几乎比使用activesupport
中的try方法快4倍require 'active_support/all'
require 'benchmark'
foo = nil
puts Benchmark.measure { 10_000_000.times { foo.try(:lala) } }
puts Benchmark.measure { 10_000_000.times { foo&.lala } }
输出
1.310000 0.000000 1.310000 ( 1.311835)
0.360000 0.000000 0.360000 ( 0.353127)
答案 2 :(得分:2)
我不认为我们应该比较这两件事,因为它们还有其他作用。
给出此示例Person
类
class Person
def name
"John"
end
end
try
。
person = Person.new
person.name # => "John"
person.email # => NoMethodError: undefined method `email' for #<Person>
person.try(:email) # => nil
如果不确定在 on 上调用方法的对象是否为空,则应使用安全导航
person = nil
person.name # => NoMethodError: undefined method `name' for nil:NilClass
person&.name # => nil
人们经常混淆这两种方法,因为您可以使用try
而不是&.
person = nil
person.name # => NoMethodError: undefined method `name' for nil:NilClass
person&.name # => nil
person.try(:name) # => nil
但是您不能使用&.
代替try
person = Person.new
person.name # => "John"
person.email # => NoMethodError: undefined method `email' for #<Person>
person.try(:email) # => nil
person&.email # NoMethodError: undefined method `email' for #<Person>