Ruby:安全导航操作符,未定义方法`call`

时间:2017-04-20 16:28:05

标签: ruby safe-navigation-operator

我正在尝试将数字文字与可能返回nil或数字的函数的返回值进行比较。考虑一下:

def unreliable
  [nil, 42].sample  
end

unreliable > 10

NoMethodError: undefined method '>' for nil:NilClass这将占50%的时间。所以我尝试了这个:

unreliable&.(:>, 10)

我希望nil保护这种方法,但是当unreliable返回42时,我会得到此信息:

NoMethodError: undefined method `call' for 42:Fixnum

我怀疑这与每个Numeric只允许一个实例存在的怪癖有关,请参阅here。而且我知道我可以这样做:

foo = unreliable
foo && foo > 10

但是有没有办法将安全导航操作符与数字和:>:<:==:+:-,{{一起使用1}},:/等?

修改:在我的问题中对:*的关注是一个红色的鲱鱼。请参阅@Jörg的回答。我把Rails的Numeric语法与安全导航操作符的语法混淆了。

2 个答案:

答案 0 :(得分:5)

这在Ruby 2.3+中运行良好:

unreliable&.> 10

例如:

[-5, 0, nil, 5].each do |unreliable|
  p unreliable&.> 0
end
# false
# false
# nil
# true

你尝试它的方式,Ruby希望unreliable是一个可调用的对象,例如Proc

unreliable = Proc.new{ |*params| puts "unreliable has been called with #{params}" }
unreliable&.(:>, 10)
# unreliable has been called with [:>, 10]
unreliable.call(:>, 10)
# unreliable has been called with [:>, 10]
unreliable&.call(:>, 10)
# unreliable has been called with [:>, 10]
unreliable[:>, 10]
# unreliable has been called with [:>, 10]

使用安全导航操作符,不需要放置parens,方法应该是方法名称,而不是符号(Rails'try需要符号)。

答案 1 :(得分:0)

  

我怀疑这与每个Numeric

只允许一个实例存在的怪癖有关

不,这与此毫无关系。

foo.(bar)

的语法糖
foo.call(bar)

Ergo,

foo&.(bar)

的语法糖
foo&.call(bar)

所以,你的代码:

unreliable&.(:>, 10)

的语法糖
unreliable&.call(:>, 10)

我不确定是谁告诉你安全导航操作员将消息作为符号参数。安全导航操作符的重点在于,通过在&前添加单个字符.,您只需要轻微的语法开销,否则表达式将保持不变。

所以,

unreliable > 10

相同
unreliable.>(10)

简单地变成

unreliable&.>(10)