块是括在括号之间的代码块{}(通常用于单行块)或do..end(用于多行块)。
5.times { puts "Hello world" } # recommended style for single line blocks 5.times do print "Hello " puts "world" end # 多行块的推荐样式 5.times { print "hello " puts "world" } # 不会引发错误,但是不建议
注意:花括号的优先级高于 do..end
可以在单词和方法内部使用块yield:
def block_caller puts "some code" yield puts "other code" end block_caller { puts "My own block" } # the block is passed as an argument to the method. #一些代码 #我自己的街区 #其他代码
请注意,如果yield不加阻塞地调用它会引发LocalJumpError。为此,ruby提供了另一种方法,block_given?该方法可让您在调用yield之前检查是否已通过块
def block_caller puts "some code" if block_given? yield else puts "default" end puts "other code" end block_caller # 一些代码 # 默认 # 其他代码 block_caller { puts "not defaulted"} # 一些代码 # 没有违约 # 其他代码
yield 也可以为块提供参数
def yield_n(n) p = yield n if block_given? p || n end yield_n(12) {|n| n + 7 } #=> 19 yield_n(4) #=> 4
尽管这是一个简单的示例,但yield对于允许直接访问另一个对象的上下文中的实例变量或评估而言,这可能非常有用。例如:
class Application def configuration @configuration ||= Configuration.new block_given? ? yield(@configuration) : @configuration end end class Configuration; end app =Application.newapp.configuration do |config| puts config.class.name end # 组态 #=> nil app.configuration #=> #<Configuration:0x2bf1d30>
如您所见,yield以这种方式使用使代码比连续调用更具可读性app.configuration.#method_name。相反,您可以在包含代码的块内执行所有配置。
块的变量是块的局部变量(类似于函数的变量),它们在执行块时消失。
my_variable = 8 3.times do |x| my_variable = x puts my_variable end puts my_variable #=> 0 # 1 # 2 # 8
块无法保存,一旦执行就会死亡。为了保存块,您需要使用procs和lambdas。