Para exact definition, I suggest looking at its Wikipedia entry. Es especialmente bueno. Solo quiero aclararlo con un ejemplo.
asume este fragmento de código C# (que se supone que realizar una búsqueda AND
en una lista):
List<string> list = new List<string> { "hello world", "goodbye world" };
IEnumerable<string> filteredList = list;
var keywords = new [] { "hello", "world" };
foreach (var keyword in keywords)
filteredList = filteredList.Where(item => item.Contains(keyword));
foreach (var s in filteredList) // closure is called here
Console.WriteLine(s);
Es un error común en C# para hacer algo así. Si observa la expresión lambda dentro de Where
, verá que define una función que su comportamiento depende del valor de una variable en su sitio de definición. Es como pasar una variable en sí misma a la función, en lugar del valor de esa variable. Efectivamente, cuando se llama a este cierre, recupera el valor de la variable keyword
en ese momento. El resultado de esta muestra es muy interesante.Imprime "Hola mundo" y "adiós mundo", que no es lo que queríamos. ¿Que pasó? Como ya he dicho anteriormente, la función que declaramos con la expresión lambda es un cierre sobre keyword
variables así que esto es lo que sucede: mundo
filteredList = filteredList.Where(item => item.Contains(keyword))
.Where(item => item.Contains(keyword));
y en el momento de la ejecución de cierre, keyword
tiene el valor" ", así que básicamente estamos filtrando la lista un par de veces con la misma palabra clave. La solución es:
foreach (var keyword in keywords) {
var temporaryVariable = keyword;
filteredList = filteredList.Where(item => item.Contains(temporaryVariable));
}
Desde temporaryVariable
tiene como alcance el cuerpo del bucle foreach
, en cada iteración, es una variable diferente. En efecto, cada cierre se vinculará a una variable distinta (esas son instancias diferentes de temporaryVariable
en cada iteración). Esta vez, se va a dar los resultados correctos ("Hola mundo"):
filteredList = filteredList.Where(item => item.Contains(temporaryVariable_1))
.Where(item => item.Contains(temporaryVariable_2));
en el que temporaryVariable_1
tiene el valor de "hola" y temporaryVariable_2
tiene el valor "mundo" en el momento de la ejecución de cierre.
Tenga en cuenta que los cierres han causado una extensión de la vida útil de las variables (se suponía que su vida terminaría después de cada iteración del ciclo). Este es también un efecto secundario importante de los cierres.
Wikipedia es particularmente bueno en las definiciones: http://en.wikipedia.org/wiki/Closure_%28computer_science%29 –
Sin embargo, las definiciones de Wikipedia como esto tiende a estar escrito por fanáticos del estrés de las tuberías y las criaturas de cristalografía (es decir, no siempre son las aves más fáciles de entender). –
El artículo de la wikipedia fue uno que leí. Dice que cualquier función de primera clase con variables libres es un cierre. Sin embargo, eso no tiene ningún sentido porque incluye todas las funciones de primera clase que devuelven valores en función de sus argumentos. ¿Implica que se convierte en un cierre cuando la función usa variables libres para crear una instancia de sus variables vinculadas? – Amaron