Frage

Ich verstehe, verwendet man die „segnen“ Schlüsselwort in Perl innerhalb einer Klasse „neue“ Methode:

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

Aber was genau „segnen“ ist dabei in diesem Hashreferenz?

War es hilfreich?

Lösung

Im Allgemeinen bless ordnet ein Objekt mit einer Klasse.

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

Wenn Sie nun eine Methode auf $object aufrufen, Perl wissen, welches Paket für die Methode zu suchen.

Wenn das zweite Argument weggelassen wird, wie in Ihrem Beispiel, die aktuelle Paket / Klasse verwendet wird.

Aus Gründen der Klarheit, Ihr Beispiel geschrieben werden könnte wie folgt aussehen:

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

EDIT: Siehe kixx ist gut beantworten für ein wenig mehr Details.

Andere Tipps

bless ordnet einen Verweis mit einem Paket.

Es spielt keine Rolle, was die Referenz zu, kann es zu einem Hash sein (häufigste Fall), zu einem Array (nicht so häufig), auf einen Skalar (in der Regel bedeutet dies, ein inside-out-Objekt ), zu einem regulären Ausdruck siehe, Unterprogramm oder Typeglob (das Buch Object Oriented Perl: Ein umfassender Leitfaden für Konzepte und Programmiertechniken durch Damian Conway für nützliche Beispiele) oder auch ein Verweis auf eine Datei oder ein Verzeichnis Griff (seltensten Fall).

Die Wirkung bless-ing hat ist, dass es eine spezielle Syntax zu dem gesegneten Verweise anwenden kann.

Zum Beispiel, wenn eine gesegnete Referenz in $obj gespeichert (assoziiert mit bless mit Paket „Class“), dann werden $obj->foo(@args) eine Subroutine foo aufrufe und übergeben als erstes Argument der Referenz $obj durch den Rest der Argumente folgen (@args) . Das Unterprogramm sollte im Paket „Klasse“ definiert werden. Wenn es kein Unterprogramm foo in Paket „Klasse“ ist, wird eine Liste von anderen Paketen (Form der Anordnung @ISA im Paket „Klasse“ gemacht) durchsucht und das erste gefundene Unterprogramm foo aufgerufen werden.

Kurzversion: es ist Markierung, dass Hash als den aktuellen Paket-Namensraum angebracht (so dass das Paket stellt seine Klassenimplementierung)

.

sagt diese Funktion wird die Einheit von REF verwiesen, dass es nun ein Objekt in der Klassenname Paket ist, oder das aktuelle Paket, wenn CLASSNAME weggelassen. Die Verwendung der zwei Argumenten von segnen wird empfohlen.

Beispiel: :

bless REF, CLASSNAME
bless REF

Rückgabewert

Diese Funktion gibt den Verweis auf ein Objekt gesegnet in CLASSNAME.

Beispiel: :

Nach dem Beispielcode ist die grundlegende Verwendung zeigt, wobei die Objektreferenz durch segnet einen Verweis auf das Paket der Klasse erstellt wird -

#!/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;
}

ich hier eine Antwort liefern werden, da hier die, die ganz für mich nicht klicken.

Perl zuordnet segnen Funktion jede Bezugnahme auf alle Funktionen in einem Paket.

Warum sollten wir brauchen das?

Lassen Sie uns beginnen, indem ein Beispiel in JavaScript ausdrücken:

(() => {
    '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
})();

können Sie nun das Klassenkonstrukt abstreifen und ohne sie auszukommen:

(() => {
    '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);    
})();

Die Funktion nimmt eine Hash-Tabelle von ungeordneten Eigenschaften (da es keinen Sinn macht, Objekte in einer bestimmten Reihenfolge in dynamischen Sprachen im Jahr 2016 zu haben zu schreiben) und gibt eine Hash-Tabelle mit diesen Eigenschaften, oder wenn Sie vergessen haben, die neuen zu setzen Stichwort, es wird den ganzen globalen Kontext (zB Fenster im Browser oder global in NodeJS) zurück.

Perl hat keine „diese“ noch „neu“ noch „Klasse“, aber es kann immer noch eine Funktion hat, die in ähnlicher Weise verhält. Wir werden nicht einen Konstruktor haben noch ein Prototyp, aber wir werden nach Belieben neue Tiere erstellen können, und ändern ihre individuellen Eigenschaften.

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

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

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

Nun, wir haben ein Problem: Was passiert, wenn wir das Tier wollen die Klänge selbst statt uns führen Druck, was ihre Stimme ist. Das heißt, wir eine Funktion performSound wollen, dass das Tier eigenen Sound druckt.

Eine Möglichkeit, dies zu tun ist, indem jedes einzelne Tier beizubringen, wie es ist Ton zu tun. Das bedeutet, dass jede Katze eine eigene doppelte Funktion performSound hat.

# 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'}();
})->();

Das ist schlecht, weil performSound als völlig neues Funktionsobjekt gesetzt wird jedes Mal ein Tier aufgebaut ist. 10000 Tiere bedeutet 10000 performSounds. Wir wollen eine einzelne Funktion performSound haben, die von allen Tieren verwendet wird, die ihren eigenen Sound und druckt sie schaut nach oben.

(() => {
    '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
})();

Hier ist, wo die parallel zu Perl irgendwie aufhört.

JavaScript Der neue Betreiber ist nicht optional, ohne sie, „dies“ innerhalb Objektmethoden korrumpiert globalen Geltungsbereich:

(() => {
    // '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.

})();

Wir wollen für jedes Tier eine Funktion haben, die eigenen Sound ist das Tieres eher nach oben aussieht, als es auf dem Bau zu.

Blessing lässt uns ein Paket als Prototyp von Objekten verwendet werden. Auf diese Weise wird das Objekt kennt das „Paket“ ist es „referenziert“, und wiederum kann die Funktionen in dem Paket „erreicht in“ die spezifischen Instanzen hat, die von dem Konstruktor dieses „Paketobjekt“ erstellt wurden:

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();

Zusammenfassung / TL; DR :

Perl hat keine "diese", "Klasse", noch "neu". um ein Objekt zu einem Paket Segen ergibt, das Objekt einen Verweis auf das Paket, und wenn es Funktionen in dem Paket nennt, werden ihre Argumente von 1 Schlitz und das erste Argument ($ _ [0] oder Verschiebung) versetzt seinen äquivalent sein wird, Javascript ist "this". Im Gegenzug können Sie etwas JavaScript Prototyp-Modell simulieren.

Leider macht es unmöglich (nach meinem Verständnis) „neue Klassen“ zur Laufzeit zu erstellen, wie Sie jede „Klasse“ brauchen ein eigenes Paket zu haben, während sie in Javascript, die Sie nicht benötigen Pakete überhaupt, als " neues“Stichwort macht eine anonyme hashmap up für Sie als Paket zur Laufzeit verwenden, den Sie neue Funktionen hinzufügen und entfernen Funktionen on the fly.

Es gibt einige Bibliotheken Perl ihre eigenen Wege zu schaffen, um diese Einschränkung in Ausdrucks Überbrückung, wie Moose.

Warum die Verwirrung :

Aufgrund der Pakete. Unsere Intuition sagt uns, das Objekt zu einem hashmap zu binden, seinen Prototyp enthält. Auf diese Weise können wir „Pakete“ zur Laufzeit wie JavaScript erstellen. Perl hat keine solche Flexibilität (zumindest nicht eingebaut, muss man es erfinden oder es aus anderen Modulen zu erhalten), und die Laufzeit Ausdruckskraft wiederum behindert. Nannte es „segnen“ macht es nicht viel Gefallen auch nicht.

Was wir tun wollen :

So etwas, sondern der Prototyp Karte rekursive verbindlicher und implizit eher auf das Prototyp gebunden werden, als dies explizit tun zu haben.

Hier ist ein naiver Versuch es: das Problem ist, dass „Call“ zu tunes weiß nicht, „was es heißt“, so kann es auch eine universelle Perl-Funktion „objectInvokeMethod (Objekt, Methode)“ sein, die das Objekt überprüft, ob die Methode hat, oder dessen Prototyp hat, oder dessen Prototyp hat es, bis es das Ende erreicht, und findet es oder nicht (prototypische inheritence). Perl hat schöne eval Magie, es zu tun, aber ich werde das für etwas lasse ich versuchen Sie es später tun können.

Auf jeden Fall hier ist die Idee:

(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'));
})->();

Auf jeden Fall wird hoffentlich jemand diesen Beitrag nützlich finden.

ich diese Gedanken Nach der Entwicklung objektorientierte Perl zu führen.

Bless beliebige Datenstruktur Bezug mit einer Klasse zuzuordnen. Bedenkt man, wie Perl erstellt die Vererbungsstruktur (in einer Art Baum) ist es einfach, den Vorteil des Objektmodells nehmen Objekte für die Komposition zu erstellen.

Für diese Assoziation wir Objekt genannt, zu entwickeln, haben immer daran, dass der innere Zustand der Objekt- und Klassen Verhaltensweisen getrennt sind. Und Sie können eine beliebige Datenreferenz segnen / erlauben alle Paket / Klasse Verhalten zu verwenden. Da das Paket „der emotional“ Zustand des Objekts verstehen.

Zum Beispiel, wenn Sie sicher sein können, dass jedes Bug Objekt ein gesegnetes Hash sein wird, können Sie (endlich!) Füllen den fehlenden Code in der Bug :: print_me Methode:

 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";
 }

Nun, wenn die print_me Verfahren über einen Verweis auf jeden Hash genannt wird, die in die Bug Klasse gesegnet worden sind, extrahiert der $ self Variable den Verweis, der als erstes Argument und dann die print-Anweisungen übergeben wurde Zugriff auf die verschiedenen Einträge des Blessed hash.

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