Ruby 块(Blocks)

示例

块是括在括号之间的代码块{}(通常用于单行块)或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。