nil 的安全导航运算符 (&.)

Safe navigation operator (&.) for nil

由于 Ruby 2.3 引入了安全导航运算符(&.),a.k.a 孤独运算符,nil 对象上的行为似乎很奇怪。

nil.nil?    # => true
nil&.nil?   # => nil

是这样设计的吗?或者在添加孤独运算符时遗漏了一些边缘情况?

对于 foo && foo.bar

foo&.bar 是 shorthand,那么您期望表达式 nil && nil.nil? 的结果是什么?

这是因为 nil&.nil? 对于 nil && nil.nil? 是 shorthand。这将评估为 nil && true,然后是 nil

对于 x.

的任何值,

(nil && x).nil? 始终计算为 true

虽然语法很强大,但这个特定案例有可能成为开发人员的'gotcha':

(stuff&.things).nil? => 这会产生 true 如果东西不存在,或者 stuff.things returns nil.

对比以下情况:

stuff&.things&.nil? => 这在每种情况下都会产生 nil 除了 stuff.things return 不是 nil 的情况,在这种情况下会 return false

由于区分 falsenil 的普通布尔逻辑存在困难,因此这在普通逻辑中不太可能有意义。

safe navigation operator: 告诉 Ruby 只有在接收者不为零时才调用下一个方法。否则,表达式 returns nil.

class 花名册 attr_accessor:球员 结束

class Player
  attr_accessor :name, :position
  
  def initialize(name, position)
    @name = name
    @position = position
  end

end

有了这两个对象,我们就可以创建一个 2 对 2 女子篮球锦标赛的名单:

moore = Player.new("Maya Moore", "Forward")
taurasi = Player.new("Diana Taurasi", "Guard")
tourney_roster1 = Roster.new
tourney_roster1.players = [moore, taurasi]

如果我们想知道我们 2 对 2 球队的前锋,我们可能会这样找到名字:

if tourney_roster1.players.first.position == "Forward"
  puts "Forward: #{tourney_roster1.players.first.name}"
end

但如果我们的对手名单设置不正确怎么办?

tourney_roster2 = Roster.new
if tourney_roster2.players.first.position == "Forward"
  puts "Forward: #{tourney_roster1.players.first.name}"
end

tourney_roster2 尚未设置任何玩家。前面的代码将引发 NoMethodError 因为 tourney_roster2.players returns nil。我们可以添加条件语句来避免这种情况,但这会使我们的 if 语句冗长且不清楚:

if tourney_roster2.players &&
   tourney_roster2.players.first &&
   tourney_roster2.players.first.position == "Forward"

相反,我们可以使用安全导航运算符来避免 NoMethodError:

if tourney_roster2.players&.first&.position == "Forward"
  puts "Forward: #{tourney_roster1.players.first.name}"
end

一些合法的用例: 安全导航运算符在处理多个对象(如此处所示)以及将方法链接在一起时派上用场。