rails on ruby,ruby on rails 之程式碼塊(二)

zyhmz發表於2018-06-11

可呼叫物件
從底層看,使用程式碼塊分為兩步。第一步,將程式碼打包備用;第二步,呼叫程式碼塊(比如通過yield語句)執行程式碼。這種“打包程式碼,以後呼叫“的機制並不是程式碼塊的專利。在Ruby中,至少還有其他三種方法可以用來打包程式碼:

  • 使用proc,proc是由塊轉換來的物件
  • 使用lambda,它是proc的變種

Proc物件
儘管Ruby中絕大多數的東西都是物件,但是程式碼塊卻不是。為什麼要重點說明這個點呢?因為假如我們想儲存一個塊供以後執行,我們就需要一個物件。
為了解決這個問題,Ruby的標準庫中提供了一個名為Proc的類。Proc就是由塊轉換過來的物件。下面我們來看看把程式碼塊轉換為Proc的三種種方式:
1. 可以使用Proc.new方法來建立一個Proc, 這個Proc#call的方法,是一種被稱為延遲執行的技巧。

inc = Proc.new {|x| x+1}
inc.call(2)   # => 3
  1. Ruby還有兩個核心方法將塊轉換為Proc:,首先介紹的是lambda方法:
dec = lambda {|x| x-1 }
dec.class    # => Proc
dec.call(2)  # => 1  
  1. 我們還可以使用一種叫帶刺的(stabby)*lambda操作符建立lambda:
p = ->(x) { x + 1 }
其實它等價於:
p = lambda {|x| x+1 }

&操作符
在絕大多數情況下,在方法中可以通過yield語句直接執行一個程式碼塊,但是在下面兩種情況下,yeild就顯得力不從心了:
1. 想把程式碼塊傳遞給另外一個方法(甚至程式碼塊)
2. 想把程式碼塊轉換成Proc
在這種情況下,我們需要給程式碼塊去一個名字,要將程式碼塊附加到一個繫結上。我們可以給這個方法新增一個特殊的引數,這個引數必須是列表中的最後一個,而且是以&符號開頭。下面我們先來舉一個&符號的例子:

def math(a, b)
   yield(a, b)
end

def do_math(a, b &operation)
    math(a, b, &operation)
end
do_math(2, 3) {|x, y| x*y}  #=>6    

但是這裡有一個漏洞,那就是如果呼叫do_math方法時沒有附加程式碼塊,那麼&operation引數將被賦值成nil,這樣math方法中的yield操作將會失敗。

下面我們再看一種將程式碼塊轉化為Proc的方式。我們再來重新回顧一下&操作符的含義:這是以一個Proc物件,但是我想把它當作程式碼塊來使用。Proc是一種用於儲存程式碼塊用於以後執行的物件。所以在程式碼中,只要我們將&去掉,就能再次得到一個Proc物件:

def my_method(&the_proc)
    the_proc
end

p = my_method {|name| "Hello, #{name}!"}
p.class        # => Proc
p.call("Bill") # => "Hello, Bill"   

當我們重新想把Proc物件轉換為程式碼塊,只要我們重新加上&操作符就好:

block/proc_to_block.rb
def my_method(greeting)
   "#{greeting}, #{yield}"
end
my_proc = proc("Bill")
my_method("Hello", &my_proc)    

相關文章