iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 10
0
Modern Web

Ruby on Rails面試題挑戰系列 第 10

Ruby on Rails面試題挑戰 Day10 - 在Ruby中的區塊(block)是什麼?

What is a block in Ruby?
在Ruby中的區塊(Block)是什麼?


今天來介紹一個在Ruby中少數不是物件的Block。

Block是do...end{...}包住的程式碼片段,Block中的程式碼會不會被執行主要是要看它「夥伴」的臉色,唯有「夥伴」(伴隨的程式)將控制權交給block時他才會被執行,舉下面程式碼說明會更加清楚。

def say_my_name(name)
  puts "My name is #{name}"
end

say_my_name("John") {puts "hello world"}
# => My name is John

雖然我們在say_my_name方法後面接了block,但這段程式碼並不會被執行,因為控制權並沒有被轉讓給block,要怎麼讓block被執行呢?

要使用yield方法,控制權會轉讓給block執行,我們將上面的方法改寫在前後都加上yield並再次執行。

def say_my_name(name)
  yield
  puts "My name is #{name}"
  yield
end

say_my_name("John") {puts "hello world"}
# =>hello world
# =>My name is John
# =>hello world 

因為呼叫say_my_name方法後,碰到yield,控制權轉讓給了block,而去執行了puts "hello world",再回來執行puts "My name is #{name}",之後又碰到yield,再一次執行控制權轉讓,所以最終結果印出了兩次hello world。

相信剛接觸Ruby的人都看過下面這種特別的寫法

3.times { puts "hello world" }
#=> hello world
#=> hello world
#=> hello world

# 也可以這樣寫
3.times do puts "hello world" end

數字3在Ruby中是個物件,而可以使用times方法,將後面的這段Block當作參數,就可以印出三次hello world。而block為什麼能被執行呢?不是說要用yield嗎,可以猜得到的是times方法裡面一定有yield將控制權轉讓出來。

另外block還有另外一個神奇的用途,能夠接收參數,接收的參數用||這個特殊的符號包住,yield轉讓控制權的時候能夠將參數送出來,看以下例子示範。

def animals
  yield "Cat"
  yield "Dog"
end

animals { |x| puts "Hello, #{x}" }
#=> Hello, Cat
#=> Hello, Dog

兩次yield代入了不同的參數給後面的block,也就印出了不同結果。

|x|裡面的x是Block裡面的區域變數,離開Block之後是無法存取的。

def animals
  yield "Cat"
  yield "Dog"
end

animals { |x| puts "Hello, #{x}" }
#=> Hello, Cat
#=> Hello, Dog

puts x #=> Error   undefined local variable or method `x'

你可以這樣回答:

Block是一段以do...end{...}包含的程式碼片段,並不會主動執行,要靠yield方法來轉移控制權給Block,Block有自己的Scope,定義在Block內的變數並不能由Block外部取得。

參考資料

  1. Ruby Programming/Ruby basics
  2. 為你自己學 Ruby on Rails

上一篇
Ruby on Rails面試題挑戰 Day09 - include與extend的差別在哪裡?
下一篇
Ruby on Rails面試題挑戰 Day11 - proc與lamba的差異是什麼?
系列文
Ruby on Rails面試題挑戰30

尚未有邦友留言

立即登入留言