Ruby - 检查block_given之间有什么区别?和!block.nil?

时间:2016-11-23 10:24:37

标签: ruby performance ruby-block

我有一个ruby方法,需要检查块是否传递给它。 一位同事建议只检查block.nil?的性能是否稍快,适用于命名块。这已经非常烦人,因为他正在使用命名块并使用block.call而不是yield来调用它,而def named_block &block if block.nil? puts "No block" else block.call end end 已被证明是significantly faster,因为命名块更易于理解可读性。

版本1:

def named_block &block
  if !block_given?
    puts "No block"
  else 
    block.call
  end
end

第2版:

block_given?

基准测试显示版本1略快于版本2,但快速查看source code似乎表明$filename = "ftp://username:password@80.1.1.1/version.txt"; $handle = fopen($filename, "r") or die("Unable to open file!"); $contents = fgets($handle); echo "Version = " . $contents . "<br>"; fclose($handle); 是线程安全的。

这两种方法有哪些主要区别?请帮我证明他错了!

3 个答案:

答案 0 :(得分:5)

首先,虽然单个nil?检查可能比block_given?更快,但捕获阻止的速度很慢。因此,除非您要捕获它,否则性能参数无效。

其次,它更容易理解。每当你看到block_given?时,你就知道究竟是什么了。当你有x.nil?时,你必须停下来思考x是什么。

第三,这是一个成语。根据我的经验,绝大多数Ruby开发人员更喜欢block_given?。在罗马的时候......

最后,您可以保持一致。如果您始终使用block_given?,问题就会解决。如果您使用nil?检查,则必须捕获该块。

  • 存在性能开销。
  • 它更冗长,是Rubyists试图避免的。
  • 命名事物是编程中最困难的事情之一。 :)你能想到块Enumerable#map的好名字吗?
  • “Grepability”是代码库的理想特征。如果你想找到你检查是否有块的所有地方,那么进行nil?检查可能会很困难。

答案 1 :(得分:0)

我认为主要区别在于block_given?可以在没有在方法定义中明确定义&block的情况下使用:

def named_block
  if !block_given?
    puts "No block"
  else 
    yield
  end
end

哪个版本在可读性方面更好?有时显式命名块可能更具可读性,有时候yield可以更具可读性。它也是个人喜好的重要组成部分。

当它加速时,在您已包含的基准测试中,yield更快。这是因为Ruby doesen不得不为块初始化新对象(Proc)并将其分配给变量。

答案 2 :(得分:-1)

还有另一种方法可以实现这一目标:

def named_block
   (Proc.new rescue puts("No block") || ->{}).call
end

▶ named_block
#⇒ No block
▶ named_block { puts 'BLOCK!' }
#⇒ BLOCK!

请不要太认真对待

UPD :正如@Lukas在评论中指出的那样,它在块上失败,引发异常⇒FIXED

相关问题