我有一个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);
是线程安全的。
这两种方法有哪些主要区别?请帮我证明他错了!
答案 0 :(得分:5)
首先,虽然单个nil?
检查可能比block_given?
更快,但捕获阻止的速度很慢。因此,除非您要捕获它,否则性能参数无效。
其次,它更容易理解。每当你看到block_given?
时,你就知道究竟是什么了。当你有x.nil?
时,你必须停下来思考x
是什么。
第三,这是一个成语。根据我的经验,绝大多数Ruby开发人员更喜欢block_given?
。在罗马的时候......
最后,您可以保持一致。如果您始终使用block_given?
,问题就会解决。如果您使用nil?
检查,则必须捕获该块。
Enumerable#map
的好名字吗?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