Вы должны начать с понимания оператора &
, как он используется здесь.См. Например:
# The & here converts a block argument to a proc
def a(&blk)
end
# The & here converts the proc to a block
a(&Proc.new { true })
В случае блока proc => он также способен превращать некоторые объекты в процессы, например:
# The symbol :class gets to_proc called here
[1].map(&:class)
Symbol#to_proc
производит то же самоеследующие функции
[1].map(&Proc.new { |x| x.class })
Я не уверен, где находится официальная документация для этого (приветствуется указатель), но из тестирования кажется, что &nil
на самом деле не передает ни один блок методу ввсе - это не имеет никакого эффекта:
def a
block_given?
end
a {} # => true
a &:puts # => true
a &nil # => false
Теперь, когда это объяснено, я могу продолжить, зачем это нужно.
Если вы опускаете парены с super
, все аргументыпередано:
class A
def initialize arg
puts arg && block_given?
end
end
class B < A
def initialize arg
super
end
end
B.new(1) {}
# prints "true" - block and arg were both passed to super
Если вы не хотите, чтобы это происходило, вы можете вручную передать аргументы super
.С этим связана проблема, к которой я вернусь после:
class A
def initialize arg1, arg2=nil
puts arg1 && !arg2
end
end
class B < A
def initialize arg1, arg2=nil
super arg1
end
end
B.new 1, 2
# prints "true" - arg1 was passed to super but not arg2
Проблема в том, что, хотя вы можете предотвратить передачу позиционных и ключевых аргументов, этот подход не помешает передаваемый блок:
class A
def initialize arg1
puts arg1 && block_given?
end
end
class B < A
def initialize arg1
super arg1
end
end
B.new(1) { }
# prints "true" - arg and block were both passed
По какой-то причине здесь важно, чтобы этого не произошло, поэтому они используют идиому, которую я раньше не видел, но, кажется, выполняет свою работу: &nil
.По сути, это говорит «ничего не передавать как блок».Я полагаю, что если вы этого не сделаете, блоки автоматически перенаправляются.