亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

Ruby 的塊

塊是 Ruby 程序員最喜歡的東西之一。它是一項非常強大的功能,使我們能夠編寫非常靈活的代碼,擁有極高的可讀性,并且可以在各處使用。本章中我們會詳細為您講解塊的使用。

1. 什么是塊

Ruby 的塊(Block)的概念在其他語言中也被稱為閉包。本質上,塊與方法是相同的,除了它沒有名稱并且不屬于對象。塊是一段接受參數并返回值的代碼并總是通過傳遞給方法來調用。

2. 如何創建一個塊

塊有兩種表達形式,一種是 do...end,用來包含多行代碼,另外一種是 {},只包含1行代碼。

實例:

5.times do
  puts "Hello, This is from inside of block."
end

#---- 輸出結果 ----
Hello, This is from inside of block.
Hello, This is from inside of block.
Hello, This is from inside of block.
Hello, This is from inside of block.
Hello, This is from inside of block.

再看另一種例子:

實例:

5.times { puts "Hello, This is from inside of block." }

#---- 輸出結果 ----
Hello, This is from inside of block.
Hello, This is from inside of block.
Hello, This is from inside of block.
Hello, This is from inside of block.
Hello, This is from inside of block.

解釋:這兩種語句完全相同,它們的含義均是向 5times 實例方法中傳遞了一個塊,而 times方法接收了塊,并執行了里面的內容。由此可見,可以簡單的將整個塊理解成可以作為方法的一個特殊參數。

Tips:在 Ruby 社區中,慣例是塊只有單行的時候使用花括號 {},每當塊多于一行的時候,使用do..end。雖然花括號也可以接收多行參數。

3. 塊如何接收參數

塊經常與哈希、數組結合成迭代器Iterators)來使用。這里我們給出了一個塊接收參數的例子。

實例:

[1, 2, 3, 4, 5].each do |number|
  puts "#{number} was passed to the block"
end

#---- 輸出結果 ----
1 was passed to the block
2 was passed to the block
3 was passed to the block
4 was passed to the block
5 was passed to the block
[1, 2, 3, 4, 5].each { |number| puts "#{number} was passed to the block" }
 
#---- 輸出結果 ----
1 was passed to the block
2 was passed to the block
3 was passed to the block
4 was passed to the block
5 was passed to the block

解釋:上面兩個例子是完全相同的,跟方法不同的是,number參數沒有使用括號(())括起來,而是使用豎線(|)的形式列出。

在迭代器(Iterators)中,我們可以通過操作塊來改變返回值。

實例:

[1, 2, 3, 4, 5].collect { |number| number + 1 }

#---- 輸出結果 ----
[2, 3, 4, 5, 6]

解釋:它調用原始數組上的collect方法,該方法為每個元素調用給定的塊,并收集該塊返回的每個返回值。然后,通過方法collect返回一個新的數組。

4. 創建一個帶有塊方法

4.1 隱形參數形式

這種形式我們會在方法后面傳入一個塊,用yield來調用塊內的方法:

實例:

def sayHello 
  yield                                  # 塊會在這里被調用
end
sayHello {puts 'Hello, This is a block'} # 傳入塊

#---- 輸出結果 ----
Hello, This is a block

它實際上和下面這個代碼是一致的:

def sayHello 
  puts 'Hello, This is a block'                      
end
sayHello

#---- 輸出結果 ----
Hello, This is a block

塊是可以多次調用的:

實例:

def sayHello 
  yield # 塊會在這里被調用
  yield # 塊會在這里第二次被調用
end
sayHello {puts 'Hello, This is a block'} # 傳入塊

#---- 輸出結果 ----
Hello, This is a block
Hello, This is a block

注意事項:當沒有塊傳入sayHello方法的時候,調用yield會拋出異常:

實例:

def sayHello 
  yield                        # 塊會在這里被調用
end
sayHello                       # 不傳入塊

#---- 輸出結果 ----
ruby.rb:2:in `sayHello': no block given (yield) (LocalJumpError)

所以,如果塊是一個可選項,我們要使用block_given?方法,僅當塊傳入的時候調用。

def sayHello 
  yield if block_given?        # 塊會在這里被調用
end
sayHello                       # 不傳入塊

# 不會拋出異常

4.2 顯式參數形式

當我們顯示聲明塊參數的時候,要使用&來標注哪個參數是塊(&后面的參數名稱是任意的。)

實例:

def sayHello &block
  block.call                             # 塊會在這里通過call來調用
end
sayHello {puts 'Hello, This is a block'} # 傳入塊

#---- 輸出結果 ----
Hello, This is a block

注意事項:顯示聲明塊參數的時候,如果不傳入塊,block的值會成為nil,所以,這種時候如果塊是可選項,我們可以通過增加判斷block來忽略塊調用部分代碼。

def sayHello &block
  block.call if block           # 塊未傳入時不會調用block.call
end
sayHello                        # 傳入塊

# 不會拋出異常

注意事項:當方法有多個參數的時候,block的參數一定要放到最后。

def sayHello name, &block
  ...
end

4.3 如何調用含有參數的代碼塊?

當我們使用隱形參數的yield來調用含有參數的代碼塊的時候我們直接將參數傳入yield,類似方法的調用形式。同樣,我們定義塊的時候,也要設置接收這個參數。

def sayHello
  yield('Andrew')
end
sayHello { |name| puts "Hello, #{name}, This is block" }

#---- 輸出結果 ----
Hello, Andrew, This is block

當我們使用顯式參數的時候,調用的形態基本一樣。

實例:

def sayHello &block
  block.call('Andrew')
end
sayHello { |name| puts "Hello, #{name}, This is block" }

#---- 輸出結果 ----
Hello, Andrew, This is block

Tips : block.arity 返回塊一共需要接收多少個參數,block.call 用來調用這個塊。

5. 小結

本章節中我們了解了塊,知道了可以通過{}創建單行的塊,也可以通過do...end創建多行的塊,我們在塊中可以使用|參數|的形式接收傳入參數。如果自己要定義帶有塊的方法的話,有隱形和顯式兩種執行塊的方式,我們同樣還可以向塊中傳入參數,形式和方法傳參是一致的。