塊是大括號 {}(通常用於單行塊)或 do..end(用於多行塊)之間的程式碼塊。

5.times { puts "Hello world" } # recommended style for single line blocks

5.times do
    print "Hello "
    puts "world"
end   # recommended style for multi-line blocks

5.times {
    print "hello "
    puts "world" } # does not throw an error but is not recommended

注意:大括號的優先順序高於 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.
#some code
#My own block
#other code

但要小心,如果在沒有阻擋的情況下呼叫 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 
# some code
# default
# other code
block_caller { puts "not defaulted"}
# some code
# not defaulted
# other code

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

雖然這是一個簡單的例子,但是 yielding 對於允許在另一個物件的上下文中直接訪問例項變數或評估非常有用。例如:

class Application
  def configuration
    @configuration ||= Configuration.new
    block_given? ? yield(@configuration) : @configuration
  end
end
class Configuration; end

app = Application.new 
app.configuration do |config| 
  puts config.class.name
end
# Configuration
#=> 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

塊無法儲存,一旦執行就會死亡。為了節省塊,你需要使用 procslambdas