Ruby - 检查 if block_given 有什么区别?和!block.nil?
Ruby - What are the differences between checking if block_given? and !block.nil?
我有一个 ruby 方法需要检查是否有块传递给它。
一位同事建议简单地检查 block.nil?
是否在性能上稍微快一些并且适用于命名块。这已经很烦人了,因为他正在使用命名块并使用 block.call
而不是 yield
调用它,后者已被证明是 significantly faster,因为命名块在术语中更容易理解可读性。
版本 1:
def named_block &block
if block.nil?
puts "No block"
else
block.call
end
end
版本 2:
def named_block &block
if !block_given?
puts "No block"
else
block.call
end
end
基准测试显示版本 1 比版本 2 稍快,但是快速查看 source code 似乎表明 block_given?
是线程安全的。
这两种方法之间的主要区别是什么?请帮我证明他是错的!
我认为主要区别在于block_given?
可以在方法定义中不显式定义&block
的情况下使用:
def named_block
if !block_given?
puts "No block"
else
yield
end
end
就可读性而言,哪个版本更好?有时显式命名块可以更具可读性,有时 yield
可以更具可读性。这也是个人喜好的问题。
就速度而言,在您包含的基准测试中,yield
更快。这是因为 Ruby 不必为块初始化新对象 (Proc
) 并将其分配给变量。
首先,虽然单个 nil?
检查可能比 block_given?
快,但捕获块的速度很慢。因此,除非您无论如何都要捕获它,否则性能参数无效。
其次,更容易理解。只要你看到 block_given?
,你就知道发生了什么。当你有了x.nil?
的时候,你要停下来想一想x
是什么
第三,成语。根据我的经验,绝大多数 Ruby 开发人员会更喜欢 block_given?
。在罗马时...
最后,你可以保持一致。如果你总是使用 block_given?
问题就解决了。如果您使用 nil?
检查,则必须捕获块。
- 存在性能开销。
- 它更冗长,这是 Ruby 主义者试图避免的。
- 命名是编程中最困难的事情之一。 :) 你能为
Enumerable#map
块取一个好名字吗?
- "Grepability" 是代码库的理想特征。如果您想找到检查您是否获得区块的所有位置,进行
nil?
检查可能会很困难。
还有另一种方法可以做到这一点:
def named_block
(Proc.new rescue puts("No block") || ->{}).call
end
▶ named_block
#⇒ No block
▶ named_block { puts 'BLOCK!' }
#⇒ BLOCK!
请不要太认真
UPD:正如@Lukas 在评论中指出的那样,它在块上失败,引发异常 ⇒ FIXED
我有一个 ruby 方法需要检查是否有块传递给它。
一位同事建议简单地检查 block.nil?
是否在性能上稍微快一些并且适用于命名块。这已经很烦人了,因为他正在使用命名块并使用 block.call
而不是 yield
调用它,后者已被证明是 significantly faster,因为命名块在术语中更容易理解可读性。
版本 1:
def named_block &block
if block.nil?
puts "No block"
else
block.call
end
end
版本 2:
def named_block &block
if !block_given?
puts "No block"
else
block.call
end
end
基准测试显示版本 1 比版本 2 稍快,但是快速查看 source code 似乎表明 block_given?
是线程安全的。
这两种方法之间的主要区别是什么?请帮我证明他是错的!
我认为主要区别在于block_given?
可以在方法定义中不显式定义&block
的情况下使用:
def named_block
if !block_given?
puts "No block"
else
yield
end
end
就可读性而言,哪个版本更好?有时显式命名块可以更具可读性,有时 yield
可以更具可读性。这也是个人喜好的问题。
就速度而言,在您包含的基准测试中,yield
更快。这是因为 Ruby 不必为块初始化新对象 (Proc
) 并将其分配给变量。
首先,虽然单个 nil?
检查可能比 block_given?
快,但捕获块的速度很慢。因此,除非您无论如何都要捕获它,否则性能参数无效。
其次,更容易理解。只要你看到 block_given?
,你就知道发生了什么。当你有了x.nil?
的时候,你要停下来想一想x
是什么
第三,成语。根据我的经验,绝大多数 Ruby 开发人员会更喜欢 block_given?
。在罗马时...
最后,你可以保持一致。如果你总是使用 block_given?
问题就解决了。如果您使用 nil?
检查,则必须捕获块。
- 存在性能开销。
- 它更冗长,这是 Ruby 主义者试图避免的。
- 命名是编程中最困难的事情之一。 :) 你能为
Enumerable#map
块取一个好名字吗? - "Grepability" 是代码库的理想特征。如果您想找到检查您是否获得区块的所有位置,进行
nil?
检查可能会很困难。
还有另一种方法可以做到这一点:
def named_block
(Proc.new rescue puts("No block") || ->{}).call
end
▶ named_block
#⇒ No block
▶ named_block { puts 'BLOCK!' }
#⇒ BLOCK!
请不要太认真
UPD:正如@Lukas 在评论中指出的那样,它在块上失败,引发异常 ⇒ FIXED