Делает `block_given?` параметр `render ‘

#ruby #yield #ruby-block

#ruby #выход #ruby-блок

Вопрос:

Меня устраивает следующее:

 def some_def(foo, amp;block)
    puts "block utilized below"
    block.call(foo)
end

def some_other_def(bar)
    puts "using yield below"
    yield bar
    puts "and back into the method"
end
  

Итак, я научился хранить блоки (и процедуры) отдельно от yield ключевого слова.

Однако я столкнулся со следующим кодом:

 # ./open_file.rb

class File
    def self.open(name, mode, amp;block)
        file = new(name, mode)
        return file unless block_given?
        yield(file)
    ensure
        file.close
    end
end
  

Кажется, параметр amp;block не имеет значения, когда я реализую execute этот код в irb:

 irb -r ./file.open.rb
  

и сделайте что-то вроде:

 File.open('foo.txt','r') {|f| puts f}
  

amp;block Отображается необязательно block_given? в:

 return file unless block_given?
  

Комментарии:

1. Вы можете использовать любую форму взаимозаменяемо.

2. amp;block параметр всегда является необязательным параметром, с или без block_given? . Однако запуск block.call (или yield , если уж на то пошло), когда block is nil (значение по умолчанию, когда оно не указано) приведет к сбоям; поэтому при amp;block использовании обычно вы захотите проверить block_given? . Таким образом, у вас есть случай обратной причинно-следственной связи : дело не в том, что это block_given? приводит amp;block к необязательности; дело в том, что amp;block необязательность заставляет программистов использовать block_given? .

3. @Amadan в этом случае вы можете просто проверить через if block .

4. @Stefan: Да, AFAIK, эти два параметра синонимичны, если есть явный параметр block . Возможно, я неправильно прочитал вопрос OP? Если OP означал » amp;block Делается ненужным с помощью block_given? «, то здесь, в некотором смысле, ответ положительный.

Ответ №1:

Как правило, вы используете amp;block аргумент только в том случае, если вам нужно передать блок другому методу, например, в этом составленном примере:

 def m(amp;block)
  some_array.map(amp;block)
end
  

или это реальная версия Enumerable#sum из Rails:

 def sum(identity = nil, amp;block)
  if block_given?
    map(amp;block).sum(identity)
  else
    sum = identity ? inject(identity, : ) : inject(: )
    sum || identity || 0
  end
end
  

В любом случае блок, с которым вызывается метод, используется при вызове другого метода, поэтому вам нужен способ ссылаться на блок (т.Е. имя).

Таким образом, block_given? / yield и amp;block служат разным целям. Возможность вызова block_given? не делает amp;block избыточным и, как в #sum описанной выше реализации, их можно даже использовать вместе.

Комментарии:

1. Интересно, почему они не использовали inject(identity) { |sum, e| sum yield(e) } вместо этого identity значение по умолчанию 0 вместо nil .

Ответ №2:

amp;block В сигнатуре метода принимает блок, преобразует его в proc и присваивает его переменной с именем block . В случае, если блок не предоставлен, он block назначается nil .

Использовать ли аргумент block в определении метода, не имеет значения, точно так же, как не имеет значения, используется ли обычный аргумент метода bar или нет в следующем определении:

 def foo(bar); end
  

Однако принятие блока в качестве параметра и неиспользование его является избыточным и пустой тратой ресурсов. Возможно, все еще имеет смысл явно указать коллеге-программисту, что метод принимает блок.

Использование block_given? не зависит от всего этого. Это не зависит от того, был ли принят блок в качестве аргумента через amp; . Он ссылается на блок напрямую, независимо от block .