2011-04-24 107 views
13

在我一千行Ruby的旅程中,我對匿名函數的概念感到非常難過。維基百科says something about代碼中有一些無名的靈魂,它提交給更高的順序,但我的理解在那裏結束。匿名函數究竟是什麼?

或換句話說,我(當我瞭解它時)會如何向我媽媽解釋匿名功能?

+0

是 「匿名函數」 的一個術語更經常在Perl社區中使用? – 2011-04-24 08:16:11

+0

和javascript社區。你可以在lisp/scheme中稱它們爲lambda表達式。 – 0112 2014-06-06 16:58:24

回答

14

匿名函數具有以下特徵:

  1. 它沒有名字(因此匿名)
  2. 是直列
  3. 使用,當你不想要一個正常功能
  4. 的開銷/手續定義
  5. 沒有明確地多次引用,除非作爲參數傳遞給另一個函數傳遞
+1

你能解釋一下_你是什麼意思嗎?「沒有明確引用多次」_?這對我來說似乎不正確。例如:'x = lambda {...}; def bar(y); @ OPTS = {回調:Y};結束; bar(x)'現在有兩個對該函數的引用,如果'bar'創建任何閉包,可能很容易就是三個。爲什麼你建議這些參考文件以某種方式使這個lambda不再是一個'匿名函數'? – Phrogz 2011-04-24 12:55:18

+0

你能解釋一下_「是在內定義」嗎?什麼東西不是_「定義內聯」_(但與您的其他標準相匹配),使其不再是_「匿名函數」_? – Phrogz 2011-04-24 12:58:49

+0

通過內聯我的意思是使用匿名函數作爲參數或在另一個函數的主體內定義等。非內聯將是一個典型的函數。 – sym3tri 2011-04-24 14:00:36

4

正如維基百科所說:一個沒有名字的函數。

這意味着您不能以典型的方式使用其名稱和參數來調用該函數。而函數本身通常是另一個函數的參數。對函數進行操作的函數稱爲「高階函數」。

考慮這個JavaScript(我知道你這個標記紅寶石,但...):

window.onload=function(){ 
      //some code here 
    } 

功能將執行在頁面加載的時候,但你可以叫不上名字來調用它,因爲它沒有一個名稱。

+2

+1此外,由於您在詢問關於ruby的知識,所以匿名ruby函數被稱爲lambdas。 – Spyros 2011-04-24 02:48:29

+0

...或塊,或過程。 – Phrogz 2011-04-24 03:04:06

12

這裏有一個前充足的紅寶石的匿名函數(稱爲在這種情況下):

my_array.each{ |item| puts item } 

哪裏是在上述匿名函數?爲什麼,它是接收單個參數的人,將其命名爲'item',然後將其打印出來。在JavaScript中,上述可以寫成...

Array.prototype.each = function(anon){ 
    for (var i=0,len=this.length;i<len;++i) anon(this[i]); 
}; 
myArray.each(function(item){ console.log(item); }); 

...這都使得它一點點清晰的一個函數被作爲參數傳遞,也有助於一個欣賞Ruby的語法。 :)

這裏還有一個匿名函數(早在紅寶石):

def count_to(n) 
    puts "I'm going to count to #{n}" 
    count = lambda do |i| 
    if (i>0) 
     count[i-1] 
     puts i 
    end 
    end 
    count[n] 
    puts "I'm done counting!" 
end 
count_to(3) 
#=> I'm going to count to 3 
#=> 1 
#=> 2 
#=> 3 
#=> I'm done counting! 

雖然例子顯然是人爲的,它展示瞭如何創建一個新的功能(在這種情況下,一個名爲計數)和分配它變爲一個變量,並將其用於主方法內的遞歸調用。 (有些人認爲這比僅僅爲遞歸創建第二種方法要好,或者用非常不同的參數重複使用遞歸主方法)。

該函數沒有名稱,該變量具有。您可以將其分配給任何數量的變量,全部使用不同的名稱。

回到第一個例子,甚至還有一個在Ruby中用於傳遞lambda作爲單一的,祝福塊語法:

print_it = lambda{ |item| puts item } 
%w[a b c].each(&print_it) 
#=> a 
#=> b 
#=> c 

...但你也可以傳遞一個lambda作爲一個正常的參數和呼叫後來,隨着這裏所示:

module Enumerable 
    def do_both_to_each(f1, f2) 
    each do |item| 
     f1[item] 
     f2[item] 
    end 
    end 
end 

print_prefix = lambda{ |i| print "#{i}*#{i} -> " } 
print_squared = lambda{ |i| puts i*i } 

(1..4).do_both_to_each(print_prefix,print_squared) 
#=> 1*1 -> 1 
#=> 2*2 -> 4 
#=> 3*3 -> 9 
#=> 4*4 -> 16 
6

在沉迷於以前的答案,匿名函數是非常有用的,當你與closures工作:

def make_adder n 
    lambda { |x| 
    x + n 
    } 
end 

t = make_adder 100 
puts t.call 1 

或(Ruby 1.9中):

def make_adder_1_9 n 
    ->(x) { 
    x + n 
    } 
end 

t_1_9 = make_adder_1_9 100 
puts t_1_9.call 1 
+3

在你的1.9例子中,你可以使用'call'的語法糖:'t_1_9。(1)'。 – 2011-04-24 09:19:48

+2

...在1.8和1.9 lambda中也可以通過't_1_9 [1]'_(它比'.call'或'。()'短,在我看來更美觀)。 – Phrogz 2011-08-16 16:12:15