42

我發現很多人可以互換使用關閉。這些人大部分都無法解釋他們在說什麼。一些Java程序員(甚至是來自非常昂貴的諮詢公司的人)都會將匿名內部類作爲「塊」和「閉包」進行討論 - 但我知道這是不正確的。 (你不能從他們在定義該方法的範圍內通過可變的變量...)「封閉」與「塊」之間的區別究竟是什麼?

我在尋找:

  • 精確,計算機科學定義的方框
  • 封閉
  • 澄清的精確,計算機科學定義在兩者之間的差異

我真的很希望看到鏈接,文章或書這些請參考

+0

我不確定他們是否有準確的定義,例如Apple添加到gcc的閉包被稱爲「塊」 – cobbal 2009-11-29 02:13:19

+0

如果您在談論[]的 - 他們從Smalltalk進入Objective-C,他們是編譯成一個名爲BlockClosure的混淆事例。 – daf 2009-11-29 02:35:23

+2

他不是在談論Objective-C,而是在談論蘋果對C的擴展。在OSX 10.6 Snow Leopard中,Appel引入了一個名爲Grand Central Dispatch的新併發庫。這是一個基於任務的庫,有點類似於微軟的Task Parallel Library。 GCD的基本思想是將一段代碼交給庫,然後庫決定何時和在哪個內核上執行。通常情況下,你可以用函數指針來做到這一點,但蘋果公司認爲這太難看了,他們用基本上是lambda表達式的C語言來擴展C,他們稱之爲塊。 – 2010-01-23 12:08:01

回答

27

雖然只是一塊可以由語句和聲明,但沒有別的組成碼,閉合是一個真正的第一類對象,其具有塊作爲其值實數變量。

主要區別在於塊簡單地將指令組合在一起(例如語句的主體),而閉包是包含一些可以執行的代碼的變量。

如果你有一個閉包,通常你可以將它作爲參數傳遞給函數,進行currify和decurrify,主要稱它爲!

Closure c = { println 'Hello!' } 
/* now you have an object that contains code */ 
c.call() 

當然倒閉更強大,他們是變量,可以用來定義對象的自定義行爲(而通常你不得不使用接口編程或其他OOP方法)。

您可以將關閉視爲包含該功能自身內部功能的函數。

塊是有用的,因爲它們允許變量的範圍。通常當你在一個範圍內定義一個變量時,你可以毫無問題地重寫外部定義,並且只有在執行塊時纔會存在新的定義。

for (int i = 0; i < 10; ++i) 
{ 
    int t = i*2; 
    printf("%d\r\n", t); 
} 

t是塊(for語句體)內定義,將持續僅僅是塊內。

+0

塊也標記「對象範圍」的開始。 – jldupont 2009-11-28 12:28:51

+0

你是對的,忘記提及..剛剛更新 – Jack 2009-11-28 12:30:46

+0

for循環的例子不會泛泛而談,因爲「閉包」與Javascript一起使用的語言比其他語言更多,並且循環塊不會封裝它們的變量除了* only *和函數聲明。我懷疑你的例子是Java?請明確說明。 – 2013-06-05 22:56:33

16

塊是語法上的東西 - 語句的邏輯單元(更多與範圍關閉)。

if (Condition) { 
    // Block here 
} 
else { 
    // Another block 
} 

的封閉涉及anoymous函數或類 - 匿名(功能)對象,一段代碼綁定到的環境(其變量)。

def foo() { 
    var x = 0 
    return() => { x += 1; return x } 
} 

這裏foo返回一個閉包!即使在foo終止之後,局部變量x仍然保留,並且可以通過調用返回的匿名函數來增加。

val counter = foo() 
print counter() // Returns 2 
print counter() // Return 3 

注意,只是紅寶石中塊和關閉都同樣對待,因爲什麼Ruby調用塊是一個關閉:

(1..10).each do |x| 
    p x 
end 

each - 方法傳遞一個閉合功能(拍攝參數x)在Ruby中被稱爲

+0

......然後就是和Smalltalk混淆了。 Ruby程序員稱之爲塊,Smalltalk稱之爲「BlockClosure」! – daf 2009-11-30 17:13:05

+0

實際上,在你的Ruby例子中,block是* not *閉包,因爲它沒有關閉任何東西。更有趣的是'a = 7; (1..10).each do | x | p a << x end'或類似的東西。 – 2010-01-23 12:00:35

1

這些日子在Ruby中最常用的術語是,儘管之前的結構出現在Algol,Smalltalk和Scheme中。如果有的話,我會引用Ruby標準。

我不確定我能回答你確切的問題,但我可以說明。我的道歉,如果你已經知道了......

def f &x 
    yield 
    x 
end 

def g 
    y = "block" 
    t = f { p "I'm a #{y}" } 
    y = "closure" 
    t 
end 

t = g 
t.call 

而且......

$ ruby exam.rb 
"I'm a block" 
"I'm a closure" 
$ 

因此,一個塊是連接到一個方法調用的代碼匿名函數樣序列。它遍佈Ruby API。當你輕鬆創建一個匿名函數時,事實證明它們對於各種事物都很有用。

但是請注意,後f回報,那麼g回報,我們從f返回它(如x)舉行的塊,然後從g(如t)。現在我們再次調用該塊。再次請注意,g()已返回。但是這個塊指的是一個不存在的函數實例(和範圍)中的局部變量?!它獲得了新的價值y?!

因此,閉包是一個類似於函數的對象,它在其詞法範圍上關閉。它們實現起來相當具有挑戰性,因爲它們會破壞對函數調用實例中局部變量非常有用的堆疊式處理模型。


1. Ruby具有各種風格的閉包函數對象;這只是其中之一。

+0

這個答案中的代碼片段是爲什麼我不使用Ruby的完美例證。 – 2016-01-14 14:35:51

2

響亮,長鬍子的人有這樣說的封鎖和塊:

http://martinfowler.com/bliki/Closure.html

在一個點上,他說,一個閉包是可以作爲參數傳遞給方法傳遞一個塊。

+0

我只是發現閉包的概念比塊更加普遍和明確。如果已經有真正的關閉,我沒有看到區塊的需要。 – 2014-04-12 20:22:18

+0

感謝您的鏈接! – 2015-01-16 22:15:31

+0

@WeiQiu正如我在上面的回答中或多或少地說過的那樣,'return'的行爲包含了塊關閉的大部分基本原理,作爲與函數關閉分離的實體。 – 2015-06-17 17:17:25

4

這裏有很多混亂,因爲有多個定義的術語,以及多個不同的事物,因爲它們通常被發現在一起而被混合。

首先,我們有「塊」。這只是一個代碼的詞彙塊,例如一個循環的主體。如果語言實際上具有塊範圍,則可以定義只存在於該塊代碼中的變量。

其次,我們有可調用代碼作爲值類型。在函數式語言中,這些是函數值 - 有時稱爲「funs」,「匿名函數」(因爲該函數可以在值中找到,而不是指定給它的名稱;你不需要名稱來調用它們),或者「 lambdas「(來自運算符,用於在教會的Lambda微積分中創建它們)。它們可能被稱爲「封閉」,但它們不是自動關閉;爲了限定它們,它們必須封裝(「關閉」)圍繞它們創建的詞法範圍 - 也就是說,定義在函數範圍之外但在定義範圍內的變量在調用函數時仍然可用,甚至如果調用點是在被引用的變量超出範圍並且其存儲被回收之後。

儘管如此,您可以擁有不是全部函數的可調用代碼值。 Smalltalk將這些「塊關閉」稱爲「塊關閉」,而Ruby將其稱爲「特效」。但大多數Rubyists只是稱它們爲「塊」,因爲它們是由{ ... }do ... end語法創建的具體化版本。是什麼使它們與lambda函數(或「函數閉包」)不同?它們不引入新的子程序級別。 如果塊閉包主體中的代碼調用return,它將從塊外部函數/方法返回,而不僅僅是塊本身。

該行爲對保留R.D. Tennent標記爲「對應原則」至關重要,該原則聲明您應該能夠用包含該代碼的內聯函數替換任何代碼並立即調用。與此

x = 2; 

:例如,在JavaScript中,你可以更換該

(function(){x = 2;})(); 

我的例子不是很有趣,但有能力做這種轉變,而不會影響的行爲程序在功能重構中起着關鍵作用。問題是,只要你嵌入return陳述,原則不再成立。

這就是爲什麼Ruby同時具有特效和lambda--這是常常引起新手混淆的原因。 procs和lambdas都是類Proc的對象,但它們的行爲不同,如上所述:一個return僅從lambda的主體返回,但它從圍繞proc的方法返回。 (另外,雖然與我在此繪製的區別無關,但如果使用錯誤數量的參數調用lambdas檢查arity併發出抱怨,您可以通過在對象上調用.lambda?來確定該類型。)

當前爲Javascript只有功能關閉,雖然在桌面上有一個建議來引入塊關閉語言。

0

這是一個整數

詮釋workDaysInAWeek = 5

這是一個整數變量並且它可以被設置爲不同的整數。 (如果情況不允許你修改的值,它可以被稱爲不變

儘管上述數字的關注,關閉關注算法。 區塊的區別也分別與上述等同。