سؤال

لقد رأيت عينات من الإغلاق من ما هو 'إغلاق'?

يمكن لأي شخص تقديم مثال بسيط عند استخدام الإغلاق ؟

وعلى وجه التحديد ، فإن السيناريوهات التي الإغلاق منطقي ؟

دعونا نفترض أن اللغة لا يجب إغلاق الدعم ، كيف يمكن للمرء أن لا تزال تحقيق نفس الشيء ؟

عدم الإساءة إلى أي شخص ، الرجاء نشر نماذج التعليمات البرمجية في لغة مثل c#, python, javascript, ruby.... الخ
أنا آسف, أنا لا أفهم اللغات الوظيفية حتى الآن.

هل كانت مفيدة؟

المحلول

الإغلاق هي ببساطة كبيرة من الأدوات.عند استخدامها ؟ في أي وقت تشاء...كما سبق أن قلت ، فإن البديل هو كتابة الطبقة ؛ على سبيل المثال ، قبل C# 2.0 ، وخلق parameterised موضوع صراع حقيقي.مع C# 2.0 أنت لا تحتاج حتى `ParameterizedThreadStart' أنت فقط تفعل:

string name = // blah
int value = // blah
new Thread((ThreadStart)delegate { DoWork(name, value);}); // or inline if short

قارن ذلك إلى خلق فئة مع اسم وقيمة

أو بالمثل مع البحث عن قائمة (باستخدام امدا هذه المرة):

Person person = list.Find(x=>x.Age > minAge && x.Region == region);

مرة أخرى - البديل سيكون لكتابة فئة مع اثنين من خصائص الأسلوب:

internal sealed class PersonFinder
{
    public PersonFinder(int minAge, string region)
    {
        this.minAge = minAge;
        this.region = region;
    }
    private readonly int minAge;
    private readonly string region;
    public bool IsMatch(Person person)
    {
        return person.Age > minAge && person.Region == region;
    }
}
...
Person person = list.Find(new PersonFinder(minAge,region).IsMatch);

هذا هو إلى حد ما مماثلة إلى كيف مترجم يفعل ذلك تحت غطاء محرك السيارة (في الواقع ، فإنه يستخدم العام قراءة/كتابة حقول خاصة للقراءة فقط).

أكبر التحذير مع C# يلتقط لمشاهدة النطاق ؛ على سبيل المثال:

        for(int i = 0 ; i < 10 ; i++) {
            ThreadPool.QueueUserWorkItem(delegate
            {
                Console.WriteLine(i);
            });
        }

هذا قد لا تتم طباعة ما كنت تتوقع ، منذ متغير لا يتم استخدام كل منها.هل يمكن أن نرى أي مزيج من يكرر حتى 10 10.تحتاج إلى بعناية نطاق القبض على المتغيرات في C#:

        for(int i = 0 ; i < 10 ; i++) {
            int j = i;
            ThreadPool.QueueUserWorkItem(delegate
            {
                Console.WriteLine(j);
            });
        }

هنا كل ي يحصل القبض على حدة (أيمختلفة مترجم إنشاء مثيل فئة).

جون السكيت لديه بلوق دخول تغطي C# و java الإغلاق هنا;أو للحصول على مزيد من التفاصيل ، انظر كتابه C# في العمق, الذي يحتوي على فصل كامل عليها.

نصائح أخرى

أنا أتفق مع الإجابة السابقة من "في كل وقت".عند برنامج في لغة وظيفية أو أي لغة حيث lambdas و إغلاق شائعة ، يمكنك استخدامها حتى من دون أن يلاحظ.كأنه يسأل "ما هو السيناريو على وظيفة ؟" أو "ما هو سيناريو حلقة؟" وهذا لا تجعل السؤال الأصلي الصوت البكم ، بل أن نشير إلى أن هناك ثوابت في اللغات التي لا تحدد في شروط سيناريوهات محددة.يمكنك فقط استخدام لهم في كل وقت, في كل شيء, انها طبيعة ثانية.

هذا هو بطريقة أو بأخرى تذكر:

المكرم سيد نا Qc كان يسير مع الطالب انطون.على أمل أن مطالبة المعلم في المناقشة ، انطون قال "يا سيد, لقد سمعت أن الكائنات هي شيء جيد جدا - هو هذا حقيقي؟" Qc نا بدا pityingly في الطلاب وأجاب: "أحمق التلميذ - الكائنات هي مجرد سوء الرجل الإغلاق."

انتقد ، أنطون أخذ إجازة من سيده وعاد إلى زنزانته ، عازمة على دراسة الإغلاق.كان بعناية قراءة كامل "لامدا:على في نهاية المطاف..." سلسلة من الأوراق و أبناء العم ، وتنفيذ صغير مخطط مترجم مع إغلاق مقرها الكائن النظام.كان تعلمت الكثير و يتطلع إلى إعلام سيده من التقدم له.

عن المشي مع مراقبة الجودة نا انطون حاولت إقناع سيده من قبل قائلا "يا سيد, لقد بجد درست هذه المسألة ، أفهم الآن أن الأشياء هي حقا رجل فقير الإغلاق." Qc نا وردت عن طريق ضرب انطون مع عصاه قائلا "عندما سوف تتعلم ؟ الإغلاق هي فقيرة الرجل كائن." في تلك اللحظة, انطون أصبح المستنير.

(http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html)

أبسط مثال على استخدام الإغلاق في ما يسمى التمشيط.في الأساس, دعونا نفترض لدينا وظيفة f() والتي عندما دعا مع اثنين من الحجج a و b, ويضيف معا.حتى في بيثون ، لدينا:

def f(a, b):
    return a + b

ولكن لنفترض جدلا أننا فقط نريد أن ندعو f() مع حجة واحدة في وقت واحد.لذا بدلا من f(2, 3), نريد f(2)(3).يمكن القيام بذلك كما يلي:

def f(a):
    def g(b): # Function-within-a-function
        return a + b # The value of a is present in the scope of g()
    return g # f() returns a one-argument function g()

الآن, عندما ندعو f(2), نحن الحصول على وظيفة جديدة ، g();هذه الوظيفة الجديدة تحمل معها متغيرات من نطاق من f(), و لذلك يقال أن إغلاق أكثر تلك المتغيرات ، وبالتالي فإن مصطلح الإغلاق.عندما ندعو g(3), متغير a (التي لا بد من تعريف f) يتم الوصول إليها من قبل g(), عودة 2 + 3 => 5

وهذا مفيد في العديد من السيناريوهات.على سبيل المثال, إذا كان لدي وظيفة التي قبلت عدد كبير من الحجج ، ولكن فقط عدد قليل منهم من المفيد لي أن أكتب وظيفة عامة مثل ذلك:

def many_arguments(a, b, c, d, e, f, g, h, i):
    return # SOMETHING

def curry(function, **curry_args):
    # call is a closure which closes over the environment of curry.
    def call(*call_args):
        # Call the function with both the curry args and the call args, returning
        # the result.
        return function(*call_args, **curry_args)
    # Return the closure.
    return call

useful_function = curry(many_arguments, a=1, b=2, c=3, d=4, e=5, f=6)

useful_function الآن المهمة التي يحتاج فقط 3 الحجج ، بدلا من 9.تجنب الاضطرار إلى تكرار نفسي ، كما خلقت عامة الحل ؛ إذا أنا أكتب آخر العديد من حجة وظيفة ، يمكنني استخدام curry الأداة مرة أخرى.

عادة ما إذا كان أحد لا يكون الإغلاق ، يجب تحديد فئة تحمل معها أي ما يعادل إغلاق البيئة و مررها.

على سبيل المثال ، في لغة مثل اللثغة ، ويمكن تعريف الدالة التي ترجع وظيفة (مع مغلقة على البيئة) لإضافة بعض مبلغ مسبقا إلى الحجة هكذا:

(defun make-adder (how-much)
  (lambda (x)
    (+ x how-much)))

واستخدامه مثل هذا:

cl-user(2): (make-adder 5)
#<Interpreted Closure (:internal make-adder) @ #x10009ef272>
cl-user(3): (funcall * 3)     ; calls the function you just made with the argument '3'.
8

في اللغة دون إغلاق ، كنت تفعل شيئا من هذا القبيل:

public class Adder {
  private int howMuch;

  public Adder(int h) {
    howMuch = h;
  }

  public int doAdd(int x) {
    return x + howMuch;
  }
}

ومن ثم استخدامها مثل هذا:

Adder addFive = new Adder(5);
int addedFive = addFive.doAdd(3);
// addedFive is now 8.

إغلاق يحمل ضمنيا بيئته ؛ يمكنك بسهولة الرجوع إلى تلك البيئة من داخل تنفيذ الجزء (لامدا).دون الإغلاق يجب أن تجعل هذه البيئة صريحة.

يجب أن أشرح لك عندما كنت استخدام الإغلاق: في كل وقت.معظم الحالات حيث الطبقة مثيل تحمل معها بعض الدولة من جزء آخر من حساب تطبيقه في أماكن أخرى بشكل أنيق محلها الإغلاق في اللغات التي تدعمها.

واحد يمكن تنفيذ كائن نظام الإغلاق.

هنا مثال من بيثون المكتبة القياسية ، inspect.py.أنه يقرأ حاليا

def strseq(object, convert, join=joinseq):
    """Recursively walk a sequence, stringifying each element."""
    if type(object) in (list, tuple):
        return join(map(lambda o, c=convert, j=join: strseq(o, c, j), object))
    else:
        return convert(object)

هذا وقد المعلمات, تحويل وظيفة الانضمام إلى وظيفة و بشكل متكرر يمشي على قوائم الصفوف.العودية يتم تنفيذها باستخدام خريطة () ، حيث المعلمة الأولى هي وظيفة.رمز يسبق دعم الإغلاق في بيثون ، لذلك يحتاج إضافية الافتراضي الحجج ، لتمرير تحويل والانضمام إلى الدعوة متكررة.مع إغلاق هذا يقرأ

def strseq(object, convert, join=joinseq):
    """Recursively walk a sequence, stringifying each element."""
    if type(object) in (list, tuple):
        return join(map(lambda o: strseq(o, convert, join), object))
    else:
        return convert(object)

في OO اللغات عادة لا تستخدم الإغلاق في كثير من الأحيان, كما يمكنك استخدام كائنات تمر الدولة - و لا بد أساليب عندما لغة لهم.عندما الثعبان لم الإغلاق ، قال الناس هذا الثعبان يحاكي الإغلاق مع الكائنات ، بينما يسب يحاكي الأشياء مع الإغلاق.كمثال من الخمول (ClassBrowser.py):

class ClassBrowser: # shortened
    def close(self, event=None):
        self.top.destroy()
        self.node.destroy()
    def init(self, flist):
        top.bind("<Escape>", self.close)

هنا النفس.قرب معلمة-أقل رد الاحتجاج به عند الهروب من الضغط.ومع ذلك ، فإن تنفيذ وثيقة لا تحتاج المعلمات - وهي ذاتي ثم ذاتي.أعلى الذاتي.عقدة.إذا كان الثعبان لم يكن بد أساليب يمكن أن تكتب

class ClassBrowser:
    def close(self, event=None):
        self.top.destroy()
        self.node.destroy()
    def init(self, flist):
        top.bind("<Escape>", lambda:self.close())

هنا لامدا الحصول على "الذات" ليس من المعلمة ، ولكن من السياق.

في لوا و الثعبان هو شيء طبيعي جدا أن تفعل عندما "فقط الترميز" لأن لحظة مرجع شيئا غير معلمة ، كنت صنع الإغلاق.(حيث أن معظم هذه سوف تكون مملة جدا كأمثلة.)

أما عن حالة ملموسة ، تخيل نظام التراجع/إعادة ، حيث الخطوات هي أزواج (التراجع () ، إعادة()) الإغلاق.أكثر تعقيدا من طرق العمل التي قد تكون إما:(أ) جعل unredoable الفئات لها طريقة خاصة مع عالميا حمقاء الحجج ، أو (ب) فئة فرعية UnReDoOperation الف مره.

كمثال آخر لانهائية القوائم:بدلا من العمل مع genericized الحاويات ، frob وظيفة استرداد العنصر التالي.(هذا هو جزء من قوة التكرار.) في هذه الحالة يمكنك إما الاحتفاظ فقط قليلا من الدولة (العدد الصحيح التالي ، قائمة-من-جميع-غير سلبي-الأعداد الصحيحة أو ما شابه) أو إشارة إلى الموقف الفعلي الحاوية.في كلتا الحالتين, انها وظيفة مراجع ما هو خارج ذاته.(في لانهائية-قائمة الحالة ، فإن الدولة المتغيرات يجب أن يكون الإغلاق المتغيرات ، لأن وإلا فإنها ستكون نظيفة عن كل مكالمة)

أنا قلت هناك أكثر يستخدم في هاسكل, ولكن لقد كان من دواعي سروري لاستخدام الإغلاق في جافا سكريبت ، في جافا سكريبت أنا لا أرى هذه النقطة.أول غريزة الصراخ "أوه لا ليس مرة أخرى" في حالة من الفوضى تنفيذ بد من جعل الإغلاق العمل.بعد أن قرأت عن كيفية الإغلاق تم تنفيذ (في جافا سكريبت على أي حال) ، فإنه لا يبدو ذلك سيئا للغاية الآن تنفيذ يبدو أنيقة إلى حد ما ، بالنسبة لي على الأقل.

ولكن من أدرك "إغلاق" ليس حقا أفضل كلمة لوصف مفهوم.أعتقد أنه من الأفضل أن يكون اسمه "الطائر نطاق."

باعتبارها واحدة من الإجابات السابقة والملاحظات كنت غالبا ما تجد نفسك باستخدام لهم دون بالكاد يلاحظ أن كنت.

مثال على ذلك هو أنها شائعة جدا في وضع واجهة المستخدم التعامل مع الحدث للحصول على إعادة استخدام التعليمات البرمجية في حين لا يزال يسمح الوصول إلى واجهة المستخدم السياق.هنا هو مثال على كيفية تحديد مجهول معالج وظيفة الحدث انقر فوق يخلق الإغلاق يشمل button و color المعلمات setColor() وظيفة:

function setColor(button, color) {

        button.addEventListener("click", function()
        {
            button.style.backgroundColor = color;
        }, false);
}

window.onload = function() {
        setColor(document.getElementById("StartButton"), "green");
        setColor(document.getElementById("StopButton"), "red");
}

ملاحظة:دقة ومن الجدير بالذكر أن إغلاق ليست في الواقع خلق حتى setColor() وظيفة مخارج.

تحتوي هذه المقالة على أمثلة اثنين من حيث الإغلاق هي في الواقع مفيدة:إغلاق

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top