Безопасный оператор навигации (&.) Для нуля

В Ruby 2.3 вводится оператор безопасной навигации (&.), он же одинокий оператор, поведение на nil объект кажется странным.

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

Это предназначено для того, чтобы вести себя так? Или какой-то крайний случай, который ускользнул при добавлении одинокого оператора?

3 ответа

Решение

foo&.bar это сокращение для foo && foo.bar, так чего бы вы ожидали от результата выражения nil && nil.nil? быть?

Это потому что nil&.nil? это сокращение для nil && nil.nil?, Это оценило бы nil && true, то есть nil,

(nil && x).nil? всегда оценивает trueдля любого значения x,

В то время как синтаксис имеет силу, этот конкретный случай имеет некоторый потенциал, чтобы стать "недоработкой" для разработчика:

(stuff&.things).nil? => Это производит true если вещи не существуют, или stuff.things возвращается nil,

против приведенного ниже случая:

stuff&.things&.nil? => Это производит nil в каждом случае, кроме случая, когда stuff.things возвращает что-то кроме nilв этом случае он вернется false,

Из-за сложности нормальной логической логики разграничения false а также nilВряд ли это будет иметь смысл в нормальной логике.

safe navigation operator:говорит Ruby вызывать следующий метод только в том случае, если получатель не равен нулю. В противном случае выражение возвращает nil.

список классов 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 возвращает 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

Некоторые законные варианты использования: оператор безопасной навигации удобен при работе с несколькими объектами, как показано здесь, и при объединении методов в цепочку.

Другие вопросы по тегам