`block_given?`会使`&block`参数可选吗?

时间:2019-03-04 02:28:06

标签: ruby yield ruby-block

我对以下内容感到满意:

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

因此,我学会了将块(和proc)与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

当我实现在irb中执行以下代码时,参数&block似乎无关紧要:

irb -r ./file.open.rb

并执行以下操作:

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

&block是否将block_given?设置为:

return file unless block_given?

2 个答案:

答案 0 :(得分:3)

通常,仅在需要将块传递给另一个方法(例如在此示例中)时才使用&block参数:

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

Enumerable#sum from 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实现一样,它们甚至可以一起使用。

答案 1 :(得分:1)

方法签名中的&block接受一个块,将其转换为proc,然后将其分配给名为block的变量。如果没有提供块,则将block分配给nil

是否在方法定义中使用参数block就像在下面的定义中是否使用普通方法参数bar一样无关紧要:

def foo(bar); end

但是,接受块作为参数而不使用它是多余的并且浪费资源。向其他程序员明确表明该方法接受一个块也许仍然有意义。

使用block_given?与此无关。它与是否已通过&将块作为参数接受无关。不管block为何,它都直接引用该块。