2012-07-25 33 views
0

我正在編寫一個簡單的事件總線以在應用程序中使用。這部分工作正常:Kernel.lambda()不返回Ruby 1.9中的lambda Proc

#!/usr/bin/env ruby 

module EventBus 
    @callbacks = {} 

    module_function 

    def on event, &callback 
    @callbacks[event] ||= [] 
    @callbacks[event].push callback 
    end 

    def fire event, *data 
    @callbacks[event].each do |callback| 
     callback.call *data 
    end 
    end 
end 

EventBus.on :foo do |x| puts x end 
EventBus.fire :foo, "test" 
# => test 

因爲我的程序的複雜性,而事實上,Proc。就拿參數非常loosey-說傻話時尚的,我想要一些說法在我的事件檢查。 lambda是這個明智的選擇:

EventBus.on :bar, &(lambda do |x| puts x end) 

# Will raise an ArgumentError, since the event was fired without any arguments 
# Remember that this is the desired behavior 
EventBus.fire :bar 

顯然,on調用的語法是醜陋的,由於&(lambda do ... end)。我寧願能夠使用do ... end(即只是傳遞一個沒有統一的&符號運算符的普通塊)並將其轉換爲lambda。我嘗試了明顯的:

... 
    def on_lambda event, &callback 
    @callbacks[event] ||= [] 
    @callbacks[event].push(lambda &callback) 
    # check if the added callback is lambda. (spoiler alert: it isn't) 
    puts @callbacks[event].last.lambda? 
    end 
end 

EventBus.on_lambda :baz do |x| puts x end 
# I would expect the callback to be a lambda, and thus throw an ArgumentError, 
# but neither of these holds. 
EventBus.fire :baz 

據我所知,on_lambda需要一個塊時,它(通過&)轉換成由callback本地引用一個Proc。我將lambdacallback的調用結果轉換回一個塊。我期望這會返回從callbackProc派生的lambda,所以我的問題是:爲什麼陣列上的元素是正常的Proc

ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux] 


更新:{ } MEGAS的提提我看着 ->() { }語法提示(我已經看到它被稱爲「刺」運算符)。它從指定的塊中生成一個lambda。這可能與我想要的普通塊語法和參數檢查的混合程度差不多。所有我需要做的就是調整的 on方法:但是

EventBus.on :bam, ->(x) do 
    puts x 
end 

我還是好奇,原來的問題,:

def on event, callback 
    @callbacks[event] ||= [] 
    @callbacks[event].push callback 
end 

,然後附加回調像這樣。

+1

什麼代碼約定使用{}針對一個行塊? – megas 2012-07-25 19:26:21

+1

就我所知,除了優先級之外,它的作用與「do ... end」等效。回調函數在我的應用程序中幾乎不會是單行的,使用該語法也不會生成lambda Proc。 – bkconrad 2012-07-25 19:43:03

回答

1

傳遞給方法調用的塊始終打包爲Procs。如果你想要lambda表達式,你必須明確地構造它們,通過說lambda {| ... | ...}。順便說一句。我也喜歡lambda比proc更好,但如果我記得好,Matz在他的教程中介紹了procs比lambdas更「功能強大」(procs「具有適應可變數量參數等的技巧」,lambda不需要)。

你不得不做這樣的事情來傳遞lambda表達式:

def on_lambda event, callback 
    (@callbacks[event] ||=[]) << callback 
    puts @callbacks[event].last.lambda? 
end 

EventBus.on_lambda :baz, lambda do |x| puts x end 
EventBus.fire :baz 
+0

這對我來說都是有意義的,但是在'on_lambda'中,我通過一元'&'運算符將Proc傳遞迴'lambda',它應該將其轉換回塊(這應該是爲什麼'lambda' doesn如果我理解正確的話,本身不會引發'ArgumentError')。 – bkconrad 2012-07-25 20:22:23

+0

另外,Proc的「技巧」一般很漂亮,但在這種情況下特別不合需要,因爲我想要嚴格的參數檢查。 – bkconrad 2012-07-25 20:25:12

+1

一旦你開始使用&...開始包裝和解包塊,這不是真正的操作員,但更多的東西像飛濺*的塊...我的意思是,一旦你開始機智&,你堅持與特效。我建議你用別名修補你的內核:λ:lambda^_^ – 2012-07-25 20:27:44