سؤال

أنا أفهم واحد يستخدم الكلمة الرئيسية "لبارك" في بيرل داخل طريقة "جديدة" في الفصل:

sub new {
    my $self = bless { };
    return $self;
}    

ولكن ما هو بالضبط "يبارك" القيام بهذا مرجع التجزئة؟

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

المحلول

بشكل عام، bless يربط كائن مع فئة.

package MyClass;
my $object = { };
bless $object, "MyClass";

الآن عند استدعاء طريقة $object, ، بيرل تعرف الحزمة للبحث عن الطريقة.

إذا تم حذف الوسيطة الثانية، كما في مثالك، يتم استخدام الحزمة / الفئة الحالية.

من أجل الوضوح، قد يتم كتابة مثالك على النحو التالي:

sub new { 
  my $class = shift; 
  my $self = { }; 
  bless $self, $class; 
} 

تحرير: انظر. kixx.'من الجيد إجابه للحصول على مزيد من التفاصيل قليلا.

نصائح أخرى

bless يربط إشارة مع حزمة.

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

التأثير bless-منح هو أنه يتيح لك تطبيق بناء جملة خاص إلى المرجع المبارك.

على سبيل المثال، إذا تم تخزين مرجع مبارك في $obj (يرتبط بها bless مع حزمة "الطبقة")، ثم $obj->foo(@args) سوف ندعو تحت الروتين foo وتمرير كوسيطة الأولى المرجع $obj تليها بقية الحجج (@args). يجب تعريف الروتين الفرعي في الحزمة "فئة". إذا لم يكن هناك روتين foo في الحزمة "فئة"، قائمة الحزم الأخرى (تؤخذ في شكل الصفيف @ISA في الحزمة "فئة") سيتم البحث عن الروتين الفرعي الأول foo وجدت سيتم استدعاء.

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

تحكي هذه الوظيفة أن الكيان المشار إليه بواسطة المرجع هو الآن كائن في حزمة ClassName، أو الحزمة الحالية إذا تم حذف classname. ينصح استخدام شكل الحجة الثانية.

مثال:

bless REF, CLASSNAME
bless REF

قيمة الإرجاع

ترجع هذه الوظيفة المرجع إلى كائن مبارك في ClassName.

مثال:

فيما يلي رمز المثال الذي يوضح استخدامه الأساسي، يتم إنشاء مرجع الكائن عن طريق نعمة مرجع إلى فئة الحزمة -

#!/usr/bin/perl

package Person;
sub new
{
    my $class = shift;
    my $self = {
        _firstName => shift,
        _lastName  => shift,
        _ssn       => shift,
    };
    # Print all the values just for clarification.
    print "First Name is $self->{_firstName}\n";
    print "Last Name is $self->{_lastName}\n";
    print "SSN is $self->{_ssn}\n";
    bless $self, $class;
    return $self;
}

سأقدم إجابة هنا لأن تلك هنا لم تنقر تماما بالنسبة لي.

يشرك وظيفة بيرل أي إشارة إلى جميع الوظائف داخل الحزمة.

لماذا نحتاج هذا؟

دعنا نبدأ بالتعبير عن مثال في جافا سكريبت:

(() => {
    'use strict';

    class Animal {
        constructor(args) {
            this.name = args.name;
            this.sound = args.sound;
        }
    }

    /* [WRONG] (global scope corruption)
     * var animal = Animal({
     *     'name': 'Jeff',
     *     'sound': 'bark'
     * }); 
     * console.log(animal.name + ', ' + animal.sound); // seems good
     * console.log(window.name); // my window's name is Jeff?
     */

    // new is important!
    var animal = new Animal(
        'name': 'Jeff',   
        'sound': 'bark'
    );

    console.log(animal.name + ', ' + animal.sound); // still fine.
    console.log(window.name); // undefined
})();

الآن يتيح تجريب بناء الفصل ولك عدم القيام به:

(() => {
    'use strict';

    var Animal = function(args) {
        this.name = args.name;
        this.sound = args.sound;
        return this; // implicit context hashmap
    };

    // the "new" causes the Animal to be unbound from global context, and 
    // rebinds it to an empty hash map before being constructed. The state is
    // now bound to animal, not the global scope.
    var animal = new Animal({
        'name': 'Jeff',
        'sound': 'bark'
    });
    console.log(animal.sound);    
})();

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

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

# self contained scope 
(sub {
    my $Animal = (sub {
        return {
            'name' => $_[0]{'name'},
            'sound' => $_[0]{'sound'}
        };
    });

    my $animal = $Animal->({
        'name' => 'Jeff',
        'sound' => 'bark'
    });

    print $animal->{sound};
})->();

الآن، لدينا مشكلة: ماذا لو كنا نريد أن يقوم الحيوان بأداء الأصوات من تلقاء أنفسهم بدلا من طباعة ما هو صوتهم. وهذا نريد أداء وظيفة يطبع صوت الحيوان الخاص.

طريقة واحدة للقيام بذلك هي عن طريق تعليم كل حيوان فردي كيفية القيام به هو الصوت. هذا يعني أن كل قطة لها وظيفة مكررة خاصة بها.

# self contained scope 
(sub {
    my $Animal = (sub {
        $name = $_[0]{'name'};
        $sound = $_[0]{'sound'};

        return {
            'name' => $name,
            'sound' => $sound,
            'performSound' => sub {
                print $sound . "\n";
            }
        };
    });

    my $animal = $Animal->({
        'name' => 'Jeff',
        'sound' => 'bark'
    });

    $animal->{'performSound'}();
})->();

هذا سيء لأن الأداء يتم وضع كائن وظيفة جديدة تماما في كل مرة يتم فيها إنشاء حيوان. 10000 الحيوانات تعني 10000 أداء. نريد أن يكون لديك أداء وظيفة واحدة تستخدمها جميع الحيوانات التي تبحث عن صوتها وطباعتها.

(() => {
    'use strict';

    /* a function that creates an Animal constructor which can be used to create animals */
    var Animal = (() => {
        /* function is important, as fat arrow does not have "this" and will not be bound to Animal. */
        var InnerAnimal = function(args) {
            this.name = args.name;
            this.sound = args.sound;
        };
        /* defined once and all animals use the same single function call */
        InnerAnimal.prototype.performSound = function() {
            console.log(this.name);
        };

        return InnerAnimal;
    })();

    /* we're gonna create an animal with arguments in different order
       because we want to be edgy. */
    var animal = new Animal({
        'sound': 'bark',
        'name': 'Jeff'
    });
    animal.performSound(); // Jeff
})();

هنا هو المكان الذي توقف الموازي مع بيرل كيندا.

مشغل JavaScript الجديد غير اختياري، وبدون ذلك، "هذه" طرق الكائنات الداخلية تفسد النطاق العالمي:

(() => {
    // 'use strict'; // uncommenting this prevents corruption and raises an error instead.

    var Person = function() {
        this.name = "Sam";
    };
//    var wrong = Person(); // oops! we have overwritten window.name or global.main.
//    console.log(window.name); // my window's name is Sam?
    var correct = new Person; // person's name is actually stored in the person now.

})();

نريد الحصول على وظيفة واحدة لكل حيوان يبحث عن صوت الحيوان الخاص بهذا الحيوان بدلا من الصغار في البناء.

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

package Animal;
sub new {
    my $packageRef = $_[0];
    my $name = $_[1]->{'name'};
    my $sound = $_[1]->{'sound'};

    my $this = {
        'name' => $name,
        'sound' => $sound
    };   

    bless($this, $packageRef);
    return $this;
}

# all animals use the same performSound to look up their sound.
sub performSound {
    my $this = shift;
    my $sound = $this->{'sound'};
    print $sound . "\n";
}

package main;
my $animal = Animal->new({
    'name' => 'Cat',
    'sound' => 'meow'
});
$animal->performSound();

ملخص / TL؛ د:

ليس لدى بيرل "هذا"، فئة "، ولا" جديد ". نعمة كائن إلى حزمة يمنح هذا الكائن مرجع إلى الحزمة، وعندما يستدعي الوظائف في الحزمة، سيتم تعويض وسيطاتها بواسطة فتحة واحدة، وستكون الوسيطة الأولى ($ _ [0] أو التحول) جافا سكريبت "هذا". بدوره، يمكنك محاكاة نموذج النموذج الأولي للجافا سكريبت.

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

هناك بعض مكتبات بيرل مما يخلق طرقا خاصة بهم لتجسيد هذا القيد في التعبير، مثل Moose.

لماذا الارتباك؟:

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

ما نريد القيام به:

شيء من هذا القبيل، ولكنه يحتوي على ملزم لخارك النموذج الأولي المكرر، ويقدم ضمنيا إلى النموذج الأولي بدلا من القيام بذلك بشكل صريح.

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

على أي حال هنا هي الفكرة:

(sub {

    my $Animal = (sub {
        my $AnimalPrototype = {
            'performSound' => sub {
                return $_[0]->{'sound'};
            }
        };

        my $call = sub {
            my $this = $_[0];
            my $proc = $_[1];

            if (exists $this->{$proc}) {
                return $this->{$proc}->();
            } else {
                return $this->{prototype}->{$proc}->($this, $proc);
            }
        };

        return sub {
            my $name = $_[0]->{name};
            my $sound = $_[0]->{sound};

            my $this = { 
                'this' => $this,
                'name' => $name,
                'sound' => $sound,
                'prototype' => $AnimalPrototype,
                'call' => $call                
            };
        };
    })->();

    my $animal = $Animal->({
        'name' => 'Jeff',
        'sound'=> 'bark'
    });
    print($animal->{call}($animal, 'performSound'));
})->();

على أي حال نأمل أن يجد شخص ما هذا المنشور مفيدا.

أنا متابعة هذا الفكر لتوجيه بيرل المنحى للكائن التطوير.

يذكر مشارك أي مرجع بنية البيانات مع فئة. بالنظر إلى كيفية إنشاء بيرل هيكل الميراث (في نوع من الشجرة)، من السهل الاستفادة من نموذج الكائن لإنشاء كائنات للتكوين.

بالنسبة لهذه الرابطة التي اتصلنا بها كائنها، في الاعتبار دائما في الاعتبار أن الحالة الداخلية للكائن والسلوكيات الفئة المنفصلة. ويمكنك أن يبارك / السماح بأي مرجع بيانات لاستخدام أي سلوكيات حزمة / فئة. نظرا لأن الحزمة يمكن أن تفهم الحالة "العاطفية" للكائن.

على سبيل المثال، إذا كنت واثقا من أن أي كائن خطأ سيكون هجا مباركا، فيمكنك (أخيرا!) قم بملء الرمز المفقود في طريقة BUG :: Print_ME:

 package Bug;
 sub print_me
 {
     my ($self) = @_;
     print "ID: $self->{id}\n";
     print "$self->{descr}\n";
     print "(Note: problem is fatal)\n" if $self->{type} eq "fatal";
 }

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

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