Безопасный оператор навигации (&.) Для нуля
В 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
Некоторые законные варианты использования: оператор безопасной навигации удобен при работе с несколькими объектами, как показано здесь, и при объединении методов в цепочку.