Frage

Ich habe festgestellt, dass viele Leute die Worte Schließung und Block austauschbar. Die meisten dieser Menschen kann nicht erklären, was sie reden.

Einige Java-Programmierer (auch solche, von wirklich teuren Beratungs) sprechen über anonyme innere Klassen als „Blöcke“ und „Verschlüsse“ - aber ich weiß, dass dies nicht wahr ist. (Sie können nicht änderbare Variablen passieren in vom Umfang des Verfahrens, in dem sie definiert sind ...)

Ich suche nach:

  • eine genaue, Informatik Definition eines Blocks
  • eine genaue, Informatik Definition eines Verschlusses
  • und Klärung der Differenz , um zwischen den beiden.

Ich möchte wirklich Links, Artikel oder Buch Verweise auf diese bitte sehen.

War es hilfreich?

Lösung

Während ein Block nur ein Stück Code, der durch die Erklärungen und zusammengesetzt werden kann, aber nichts anderes, eine Schließung ist ein echtes First-Class-Objekt, ein echten Variable, die einen Block als seinen Wert hat.

Der wesentliche Unterschied besteht darin, dass ein Block einfach Gruppen Anweisungen zusammen (zum Beispiel des Körper eines , während statement), während ein Verschluss eine Variable, die einen Code enthält, der ausgeführt werden kann.

Wenn Sie einen Verschluss in der Regel können Sie es als Parameter an Funktionen übergeben, currify und decurrify es, und vor allem es nennen!

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

Natürlich Schließungen mächtiger sind, sind sie Variablen und können verwendet werden, um benutzerdefiniertes Verhalten von Objekten zu definieren (während in der Regel verwenden Sie mußten Schnittstellen oder andere OOP Ansätze in der Programmierung).

Sie können denken Sie an einen Schließung als Funktion, das enthält, was diese Funktion in sich selbst tut.

Die Blöcke sind nützlich, weil sie Scoping von Variablen ermöglichen. Normalerweise, wenn Sie eine Variable innerhalb eines Bereichs definieren können Sie die äußeren Definitionen ohne Probleme außer Kraft setzen und neue Definitionen werden nur während der Ausführung des Blocks vorhanden sind.

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

t wird innerhalb des Blocks (der Körper der for Anweisung) definiert und wird nur innerhalb dieses Blocks dauern.

Andere Tipps

Ein Block ist etwas syntaktisch -. Eine logische Einheit von Anweisungen (mehr im Zusammenhang mit Anwendungsbereich als zu Schließung )

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

Ein Verschluss anoymous Funktionen oder Klassen verwendet ist -. Ein anonymes (Funktion) Objekt, ein Stück Code, der an eine Umgebung gebunden ist (mit seinen Variablen)

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

Hier foo gibt einen Verschluss! Die lokale Variable x bleibt durch den Verschluss auch nach foo beendet und kann durch Anrufe der zurückgegebenen anonymen Funktion erhöht werden.

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

Beachten Sie, dass Ruby ist nur in dem Block und Schließung behandelt werden ähnlich da, was Rubin nennt Block ist ein Verschluss:

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

Es each-Methode wird eine Verschlussfunktion übergeben (unter einem Parameter x), die aufgerufen wird, ein Block in Ruby.

Es gibt eine Menge Verwirrung hier, weil es Begriffe mit mehreren Definitionen, und mehr verschiedenen Dingen, die einfach verschmelzt erhalten, weil sie in der Regel zusammen gefunden sind.

Erstens haben wir "Block". Das ist nur ein lexikalischer Teil des Codes, der eine Einheit bildet - den Körper einer Schleife, zum Beispiel. Wenn die Sprache tatsächlich Umfang blockieren, dann können Variablen definiert werden, dass nur innerhalb dieses Stück Code vorhanden sind.

Zweitens haben wir aufrufbar Code als Werttyp. In funktionalen Sprachen sind diese Funktionswerte - manchmal auch als „Spaßten“, „anonyme Funktionen“ (da die Funktion in dem Wert gefunden wird, nicht seinen Name zugewiesen, Sie müssen keinen Namen, sie nennen), oder " Lambda-Ausdrücke“(von dem Bediener erstellen sie in Kirche Lambda-Kalkül verwendet). Sie können „Verschlüsse“, aber sie sind nicht automatisch wahr Verschlüsse genannt werden; um sich zu qualifizieren, müssen sie ( „schließen over“), um die lexikalischen Gültigkeitsbereich rund um ihre Schöpfung kapseln - das heißt, nicht in den Anwendungsbereich der Funktion definierten Variablen selbst, sondern im Rahmen ihrer Definition noch zur Verfügung stehen, wenn die Funktion aufgerufen wird, auch wenn der anrufende Punkt nach der referenzierten Variable sonst außerhalb des Gültigkeitsbereichs gegangen wäre und hatte seine Lagerung zurückgeführt.

Zum Beispiel betrachtet diese Javascript:

function makeClosure() {
  var x = "Remember me!";
  return function() {
    return "x='" + x + "'";
  }
}

// console.log(x); 
// The above is an error; x is undefined
var f = makeClosure();
console.log(f());
// The above outputs a string that includes x as it existed when f was created.

Die Variable x definiert ist nur innerhalb des Körpers der Funktion makeClosure; außerhalb dieser Definition, existiert es nicht. Nachdem wir makeClosure rufen, erklärte die x Inneren verschwunden sein sollte. Und es ist, aus der Sicht des meisten des Codes. Aber die Funktion von makeClosure zurückgegeben wurde erklärt, während x existierte, so hat es immer noch Zugriff darauf, wenn Sie es später nennen. Das macht es ein echter Verschluss.

Sie können die Funktionswerte haben, die nicht Verschlüsse sind, weil sie Umfang nicht bewahren. Sie können auch Teilschließungen haben; PHP Funktionswerte erhalten nur bestimmte Variablen, die zu dem Zeitpunkt wird der Wert erstellt aufgelistet werden müssen.

Sie können auch aufrufbar Codewerte haben, die ganzen Funktionen überhaupt nicht vertreten. Smalltalk nennt diese „Block Verschlüsse“ und Ruby ihnen „Procs“ nennt, obwohl viele Rubyisten sie nur als „Blöcke“, weil sie die verdinglichte Version von dem, was von der { ... } erstellt wird oder do ... end Syntax . Was macht sie aus lambda distinct (oder „Funktionshüllen“) ist, dass sie keine neue Aufrufebene einzuführen. Wenn der Code in den Körper eines Blockabschluss return aufruft, gibt es von der äußeren Funktion / Methode der Block Schließung innerhalb existiert, nicht nur der Block selbst.

Dieses Verhalten ist von entscheidender Bedeutung für die Erhaltung, was R. D. Tennent das „Korrespondenzprinzip“ bezeichnet, in dem es heißt, dass Sie mit einer Inline-Funktion beliebigen Code ersetzen können, sollte sofort, dass Code in den Körper und rief enthält. Zum Beispiel in Javascript, können Sie diese ersetzen:

x=2
console.log(x)

mit dieser:

(function(){x = 2;})();
console.log(x)

Dieses Beispiel ist nicht sehr interessant, aber die Fähigkeit, diese Art von Transformation zu tun, ohne das Verhalten des Programms zu beeinflussen spielt eine Schlüsselrolle in der funktionellen Refactoring. Aber mit Lambda-Ausdrücke, sobald Sie return Anweisungen eingebettet haben, das Prinzip nicht mehr gilt:

function foo1() {
  if (1) {
    return;
  }
  console.log("foo1: This should never run.")
}
foo1()
function foo2() {
  if (1) {
    (function() { return; })();
  }
  console.log("foo2: This should never run.")
}
foo2()

Die zweite Funktion unterscheidet sich von der ersten; die console.log ausgeführt wird, weil die return nur aus der anonymen Funktion zurückgibt, nicht von foo2. Dies bricht das Korrespondenzprinzip.

Aus diesem Grunde Rubin beiden Procs und Lambda hat, obwohl die Unterscheidung eine beständige Quelle der Verwirrung für Neulinge ist. Beide Procs und Lambdas sind Objekte der Klasse Proc, aber sie verhalten sich anders, wie oben angegeben: ein return nur aus dem Körper eines Lambda gibt, aber es kehrt aus dem Verfahren eine proc umgebenden

.
def test
  p = proc do return 1 end
  l = lambda do return 1 end
  r = l[]
  puts "Called l, got #{r}, still here."
  r = p[]
  puts "Called p, got #{r}, still here?"
end

Das oben gezeigt test Verfahren wird nie auf die zweite puts bekommen, weil der Aufruf von p test verursachen wird sofort zurückkehren (mit einem Rückgabewert von 1). Wenn Javascript Block Schließungen hatte, konnte man das gleiche tun, aber es funktioniert nicht (obwohl es ein Vorschlag, um sie hinzuzufügen ist).

Die lautet, Bärtige hat dies zu sagen über Schließungen und Blöcke:

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

An einer Stelle sagt er ein Verschluss ein Block, der als Argument an eine Methode übergeben werden kann.

Die Begriffe, die Sie verwenden, werden am häufigsten verwendet zusammen in diesen Tagen in Ruby, obwohl die Konstrukte zuvor erschien in Algol, Smalltalk und Schema. Ich würde den Ruby-Standard zitieren, wenn es eine ist.

Ich bin nicht sicher, ob ich in der Lage Ihre genaue Frage zu beantworten, aber ich kann illustrieren. Ich entschuldige mich, wenn Sie wissen, dass dies schon ...

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

Und ...

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

So ein Block eine anonyme Funktion artige Abfolge von Code zu einem Methodenaufruf angebracht. Es ist alles über das Ruby-API verwendet. Wenn Sie es einfach genug, um eine anonyme Funktion zu erstellen, es stellt sich heraus, dass sie für alle Arten von Dingen nützlich sind.

Beachten Sie jedoch, dass nach f zurückkehrt, kehrt g, wir auf den Block gehalten auf, indem es von f (als x) zurückkehren und dann von g (als t). Nun rufen wir den Block ein zweites Mal. Auch hier ist zu beachten, dass g() zurückgekehrt ist. Aber der Block bezieht sich auf eine lokale Variable in einer Funktionsinstanz (und Umfang), die nicht mehr existiert ?! Und es wird den neuen Wert von y ?!

So ein Verschluss ist ein funktionsähnliche Objekt, das über seinen lexikalischen Gültigkeitsbereich geschlossen ist. Sie sind sehr anspruchsvoll zu implementieren, da sie das Do-it-mit-einem-Stack-Modell zerstören, die für lokale Variablen in Funktionsaufruf Instanzen so nützlich ist.


1. Ruby hat verschiedene Aromen von Verschlussartigen Funktionsobjekte; Dies ist nur einer von ihnen.

  

5

Das ist ein integer .

  

Int workDaysInAWeek = 5

Das ist ein Integer-Variable und es kann zu einem anderen gesetzt werden integer . (Wenn es die Umstände verhindern, dass Sie diesen Wert ändern, kann es so genannte Konstante werden.)

Während der oben Sorge Zahlen, Blöcke und Verschlüsse Sorge Algorithmen. Die Unterscheidung zwischen Blocks und Verschlüsse bzw. ist auch äquivalent zu den oben genannten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top