Может ли параметр block_given отображать параметр & block? - PullRequest
0 голосов
/ 04 марта 2019

Мне удобно следующее:

def some_def(foo, &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, &block)
        file = new(name, mode)
        return file unless block_given?
        yield(file)
    ensure
        file.close
    end
end

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

irb -r ./file.open.rb

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

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

Является ли &block необязательным для block_given? in:

return file unless block_given?

Ответы [ 2 ]

0 голосов
/ 04 марта 2019

&block в сигнатуре метода принимает блок, преобразует его в процесс и назначает его переменной с именем block.Если блок не предоставлен, block назначается nil.

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

def foo(bar); end

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

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

0 голосов
/ 04 марта 2019

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

def m(&block)
  some_array.map(&block)
end

или настоящей реальной версии Enumerable#sumfrom Rails :

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

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

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

...