42

Zauważyłem, że wiele osób używa zamiennie słów zamknięcie i blok. Większość z tych osób nie potrafi wyjaśnić, o czym mówią.Dokładnie jaka jest różnica między "zamknięciem" a "blokiem"?

Niektórzy programiści Java (nawet z bardzo drogich firm konsultingowych) mówią o anonimowych klasach wewnętrznych jako "blokach" i "zamknięciach" - ale wiem, że to nieprawda. (Nie można przekazać zmienne zmienny w zakresie od sposobu, w którym są one zdefiniowane ...)

Szukam:

  • precyzyjny, informatyka definicja blokować
  • precyzyjne, informatyka definicję zamknięcia
  • i klarowania na różnicy między nimi.

Chciałbym zobaczyć linki, artykuły lub książki o numerach na ten temat pod numerem.

+0

Nie jestem pewien, czy mają precyzyjne definicje, na przykład zamknięcia dodane przez Apple do gcc nazywane są "blokami" – cobbal

+0

Jeśli mówisz o [] - dostali się do Celu C z Smalltalk, gdzie są wkompilowane w instancję myląco nazwaną "BlockClosure". – daf

+2

Nie mówi o Objective-C, mówi o rozszerzeniach Apple'a na C. W OSX 10.6 Snow Leopard, Appel wprowadził nową bibliotekę współbieżności zwaną Grand Central Dispatch. Jest to biblioteka oparta na zadaniach, podobna do biblioteki Task Parallel Library firmy Microsoft. Podstawową ideą GCD jest przekazanie bloku kodu do biblioteki, a biblioteka decyduje, kiedy i na jakim rdzeniu ma zostać wykonany. Zwykle robiłbyś to za pomocą wskaźników funkcji, ale Apple uznał to za zbyt brzydkie i rozszerzyło C o zasadniczo wyrażenia lambda, które nazywają blokami. –

Odpowiedz

27

Choć blok jest tylko kawałek kodu, który może składać oświadczenia i deklaracje, ale nic innego, zamknięcie jest prawdziwym pierwszej klasy obiekt, prawdziwy zmienną, która ma blok jako jego wartości.

Główna różnica polega na tym, że blok po prostu grupuje instrukcje razem (na przykład treść instrukcji podczas gdy), podczas gdy zamknięcie jest zmienną zawierającą kod, który można wykonać.

Jeśli masz zamknięcie, zwykle możesz przekazać je jako parametr do funkcji, curry i decurrify go, a przede wszystkim zadzwoń!

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

zamknięć oczywiście są bardziej wydajne, są zmienne i mogą być wykorzystane do zdefiniowania niestandardowego zachowania obiektów (podczas gdy zwykle trzeba było użyć interfejsy lub w innych podejściach OOP programowanie).

Możesz myśleć o zamknięciu zamknięcie jako funkcji, która zawiera to, co ta funkcja robi w sobie.

Bloki są przydatne, ponieważ pozwalają na ustalanie zakresu zmiennych. Zwykle, gdy definiujesz zmienną wewnątrz zakresu, możesz nadpisać zewnętrzne definicje bez żadnych problemów, a nowe definicje będą istniały tuż podczas wykonywania bloku.

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

t jest zdefiniowana wewnątrz bloku (ciało zestawienia for) i potrwa tylko wewnątrz tego bloku.

+0

blok oznacza także początek "zakresu obiektu". – jldupont

+0

Masz rację, zapomniałeś wspomnieć o tym, że ... właśnie zaktualizowany – Jack

+0

Przykład for-loop nie jest generowany w locie, ponieważ "zamknięcie" jest słownikiem używanym z Javascriptem bardziej niż z innymi językami, a bloki pętli nie zawierają w ogóle ich zmiennych oprócz * tylko * z deklaracjami funkcji. Podejrzewam, że twoim przykładem jest Java? Proszę sprecyzuj. –

16

Blok jest coś syntaktyczna - jednostka logiczna wypowiedzi (podobne do zakresu niż zamknięcia).

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

Zamknięcie związane jest z anoymous funkcji lub klas - anonimowy (funkcyjny) obiektu, kawałek kodu, który jest związany z otoczenia (z jego zmiennych).

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

Tutaj foo zwraca zamknięcie! Zmienna lokalna x utrzymuje się przez zamknięcie nawet po zakończeniu foo i może zostać zwiększona poprzez wywołania zwróconej anonimowej funkcji.

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

Należy pamiętać, że tylko Ruby, w którym blok i zamknięcia są traktowane podobnie, ponieważ to, co nazywa Ruby blok jest zamknięcie:

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

Nie each -method przepuszcza funkcję zamykającą (biorąc parametr x), który jest nazywany blokiem w Rubim.

+0

... to jest zamieszanie z Smalltalk. Czego programiści Rubiego nazywają blokiem, Smalltalk nazywa 'BlockClosure'! – daf

+0

W rzeczywistości, w twoim przykładzie z Ruby, blok nie jest * zamknięciem, ponieważ nie zamyka się na niczym. Bardziej interesujące byłoby "a = 7; (1..10) .each do | x | p << << koniec' lub coś podobnego. –

1

Terminy, z których korzystasz są najczęściej używane razem tych dni w Ruby, chociaż konstrukcje wcześniej pojawiły się w Algol, Smalltalk i Scheme. Chciałbym zacytować standard Ruby, jeśli taki był.

Nie jestem pewien, czy jestem w stanie odpowiedzieć na Twoje dokładne pytanie, ale mogę je zilustrować. Przepraszam, jeśli wiesz, że to już ...

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 

I ...

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

Więc blok jest anonimowy sekwencja funkcja podobny kod dołączony do wywołania metody. Jest używany w całym interfejsie API Ruby. Kiedy ułatwisz tworzenie anonimowej funkcji, okazuje się, że są one przydatne w przypadku wszystkich rodzajów rzeczy.

jednak pamiętać, że po fg zwrotów, potem wraca, przeprowadziliśmy się do bloku poprzez jego zwrot od f (jak x), a następnie z g (jak t). Teraz nazywamy blok po raz drugi. Znowu zauważ, że powrócił g(). Ale blok odnosi się do zmiennej lokalnej w instancji funkcji (i zasięgu), która już nie istnieje ?! I dostaje nową wartość y?!

Tak więc zamknięcie to obiekt podobny do funkcji, który jest zamknięty w swoim zakresie leksykalnym. Są dość trudne do wdrożenia, ponieważ niszczą model "zrób to sam z stosem", który jest tak przydatny dla zmiennych lokalnych w instancjach wywołania funkcji.


1. Ruby ma różne smaki obiektów funkcyjnych podobnych do zamknięcia; to tylko jeden z nich.

+0

Fragment kodu w tej odpowiedzi doskonale ilustruje, dlaczego nie używam Rubiego. –

2

Głośny, brodaty ma do powiedzenia na temat zamknięcia i bloków:

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

W pewnym momencie mówi zamknięcie jest blok, który może być przekazany jako argument do metody.

+0

Po prostu uważam, że pojęcie zamknięcia jest znacznie bardziej ogólne i lepiej zdefiniowane niż blok. Nie widziałem potrzeby bloków, jeśli w pobliżu są już rzeczywiste zamknięcia. –

+0

Dzięki za link! –

+0

@WeiQiu Jak już mówiłem w powyższej odpowiedzi, zachowanie 'return' zawiera większość uzasadnień dla zamknięć bloków jako oddzielnych jednostek od zamknięć funkcji. –

4

Tutaj jest dużo zamieszania, ponieważ istnieją terminy z wieloma definicjami i wieloma różnymi rzeczami, które łączą się ze sobą po prostu dlatego, że zwykle występują razem.

Po pierwsze, mamy "blok". To tylko leksykalny fragment kodu, który tworzy jednostkę - na przykład ciało pętli. Jeśli język rzeczywiście ma zasięg blokowy, wówczas można zdefiniować zmienne, które istnieją tylko w tym fragmencie kodu.

Po drugie, mamy kod wywoływalny jako typ wartości. W językach funkcjonalnych są to wartości funkcyjne - czasami nazywane "funkcjami", "funkcjami anonimowymi" (ponieważ funkcja znajduje się w wartości, a nie jej nazwa jest przypisana, nie trzeba nazwy, aby je wywoływać), lub " lambdas "(od operatora użytego do stworzenia ich w Kościele Lambda Rachunek). Można je nazywać "zamknięciami", ale nie są one automatycznie prawdziwymi zamknięciami; aby się zakwalifikować, muszą hermetyzować ("zamknąć") zakres leksykalny otaczający ich tworzenie - to znaczy zmienne zdefiniowane poza zakresem samej funkcji, ale w zakresie jej definicji są nadal dostępne za każdym razem, gdy funkcja jest wywoływana, nawet jeśli punkt wywołania jest po tym, jak zmienna odniesienia w przeciwnym razie wykroczyłaby poza zakres i została poddana recyklingowi.

Można jednak wywoływać wartości kodu, które nie są pełnymi funkcjami. Smalltalk nazywa te "zamknięcia bloków", a Ruby nazywa je "procami". Ale większość Rubyistów nazywa je po prostu "blokami", ponieważ są one poprawioną wersją tego, co zostało utworzone przez składnię { ... lubTo, co odróżnia je od lambdów (lub "zamknięć funkcji"), to to, że nie wprowadzają nowego poziomu podprogramu. Jeśli kod w treści zamknięcia bloku wywołuje return, zwraca on z zewnętrznej funkcji/metody, w której istnieje zamknięcie bloku, a nie tylko sam blok.

Takie zachowanie ma kluczowe znaczenie dla zachowania tego, co R.D. Tennent nazwał "zasadą korespondencji", która mówi, że powinieneś być w stanie zamienić dowolny kod na wbudowaną funkcję zawierającą ten kod w ciele i natychmiast zadzwonić. Na przykład, w JavaScripcie, można zastąpić to:

x = 2; 

z tym:

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

mój przykład nie jest bardzo ciekawe, ale zdolność do tego rodzaju transformacji, nie wpływając na zachowanie tego Program odgrywa kluczową rolę w refakturach funkcjonalnych. Problem polega na tym, że zaraz po tym, jak masz wbudowane oświadczenia return, zasada już nie istnieje.

To dlatego Ruby ma zarówno procsy, jak i lambdy - odwieczne źródło zamieszania dla początkujących. Zarówno procsy, jak i lambdy są obiektami klasy Proc, ale zachowują się inaczej, jak wskazano powyżej: a return po prostu wraca z ciała lambda, ale powraca z metody otaczającej proc. (Również, gdy nie pasuję do rozróżnienia, które tutaj rysuję, lambdas sprawdza się i narzeka, jeśli zostanie wywołany z niewłaściwą liczbą argumentów.) Możesz powiedzieć, jaki masz typ, dzwoniąc pod numer .lambda?.

Obecnie Javascript ma tylko funkcje zamknięcia, chociaż na stole jest propozycja wprowadzenia bloków zamkniętych dla języka.

0

To całkowitą.

Int workDaysInAWeek = 5

To jest zmienną całkowitą i może być ustawiona na różnych całkowitej. (Jeżeli okoliczności uniemożliwiają modyfikację tej wartości, to można nazwać stałą.)

Zważywszy powyższe dotyczą liczb bloki i zamknięcia dotyczą algorytmów. Rozróżnienie między blokami i , odpowiednio, jest również równoważne powyższym.