Domanda

Capisco si usa il "benedire" parola chiave in Perl all'interno "nuovo" metodo di una classe:

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

Ma che cosa è esattamente "benedire" facendo a quello di riferimento hash?

È stato utile?

Soluzione

In generale, bless associa un oggetto con una classe.

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

Ora, quando si richiama un metodo su $object, Perl sa quale pacchetto per la ricerca per il metodo.

Se il secondo argomento viene omesso, come nel tuo esempio, viene utilizzato l'attuale pacchetto / classe.

Per motivi di chiarezza, il tuo esempio potrebbe essere scritto come segue:

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

EDIT: Vedere KiXX E 'bene rispondere per un po 'più in dettaglio.

Altri suggerimenti

bless associa un riferimento a un pacchetto.

Non importa quanto il riferimento è, può essere quello di un hash (caso più comune), ad una matrice (non comune), ad uno scalare (di solito questo indica un dentro-fuori oggetto ), ad un'espressione regolare , subroutine o typeglob (vedere il libro Object Oriented Perl: Una guida completa ai concetti e tecniche di programmazione per Damian Conway per esempi utili) o anche un riferimento a un handle di file o una directory (caso meno comune).

L'effetto bless-ing ha è che consente di applicare la sintassi speciale per il riferimento benedetto.

Ad esempio, se viene memorizzato un riferimento blessed in $obj (associata da bless con pacchetto "Classe"), allora $obj->foo(@args) chiamerà un foo subroutine e passare come primo argomento $obj riferimento seguito dal resto degli argomenti (@args) . La subroutine dovrebbe essere definito in pacchetto "di classe". Se non c'è foo subroutine nel pacchetto "Class", una lista di altri pacchetti (preso forma il @ISA matrice nel pacchetto "Class") sarà cercato e il primo foo subroutine trovato sarà chiamato.

Versione corta: è la marcatura che hash come allegato al namespace pacchetto corrente (in modo che il pacchetto prevede la sua attuazione classe)

.

Questa funzione indica l'entità a cui fa riferimento REF che ora è un oggetto nel pacchetto CLASSNAME, o il pacchetto corrente se NOMECLASSE viene omesso. Si consiglia l'uso della forma a due argomenti di bless.

Esempio :

bless REF, CLASSNAME
bless REF

Valore di ritorno

Questa funzione restituisce il riferimento ad un oggetto benedetto in NOMECLASSE.

Esempio :

Di seguito è riportato il codice di esempio che mostra il suo utilizzo di base, si crea il riferimento all'oggetto benedicendo un riferimento alla classe del package -

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

fornirò una risposta qui dal momento che quelli qui non del tutto clicca per me.

funzione di benedire Perl associa ogni riferimento a tutte le funzioni all'interno di un pacchetto.

Perché avremmo bisogno di questo?

Cominciamo esprimendo un esempio in JavaScript:

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

Ora lascia spogliare il costrutto di classe e fare a meno di esso:

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

La funzione prende una tabella hash di proprietà non ordinate (in quanto non ha senso dover scrivere le proprietà in un ordine specifico in linguaggi dinamici nel 2016) e restituisce una tabella hash con quelle proprietà, o se avete dimenticato di mettere la nuova parola chiave, verrà restituito l'intero contesto globale (ad esempio finestra del browser o globale in nodejs).

Perl non ha "questo" o "nuovo", né "di classe", ma può ancora avere una funzione che si comporta in modo simile. Noi non abbiamo un costruttore né un prototipo, ma saremo in grado di creare nuovi animali a volontà e modificarne le proprietà individuali.

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

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

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

Ora, abbiamo un problema: cosa succede se vogliamo che l'animale per eseguire i suoni da soli invece di stampa ciò che la loro voce è. Cioè, noi vogliamo una funzione performSound che stampa proprio suono dell'animale.

Un modo per farlo è attraverso l'insegnamento di ogni singolo animale come farlo è suono. Ciò significa che ogni gatto ha una sua funzione duplicato performSound.

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

Questo è male perché performSound è messo come un nuovo oggetto funzione ogni volta che un animale è costruito. 10000 animali significa 10000 performSounds. Vogliamo avere un unico performSound funzione che viene utilizzato da tutti gli animali che guarda in alto il proprio sound e lo stampa.

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

Qui è dove il parallelo a Perl si ferma un pò.

nuovo operatore di JavaScript non è un optional, senza di essa, "questo" dentro i metodi degli oggetti corrompe portata globale:

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

})();

Vogliamo avere una funzione per ogni animale che guarda in alto proprio suono di quella degli animali invece di inserirli nel codice a costruzione.

Benedizione permette di usare un pacchetto come il prototipo degli oggetti. In questo modo, l'oggetto è a conoscenza del "pacchetto" si "ha fatto riferimento a", e, a sua volta può avere le funzioni del pacchetto "raggiungere nel" le istanze specifiche che sono stati creati dal costruttore che "oggetto pacchetto":

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

Riepilogo / TL; DR :

Perl non ha "questo", "classe", né "nuovo". benedizione un oggetto a un pacchetto dà quell'oggetto un riferimento al pacchetto, e quando chiama le funzioni nel pacchetto, i loro argomenti sarà compensato da 1 slot, e il primo argomento ($ _ [0] o spostamento) sarà pari a di "questo" javascript. A sua volta, è possibile in qualche modo simulare il prototipo di JavaScript.

Purtroppo rende impossibile (la mia comprensione) per creare "nuove classi" in fase di esecuzione, come avete bisogno di ogni "classe" per avere il suo proprio pacchetto, mentre in javascript, non hai bisogno di pacchetti a tutti, come " nuova" parola chiave costituisce un hashmap anonimo per l'uso come un pacchetto in fase di esecuzione a cui è possibile aggiungere nuove funzioni e rimuovere funzioni al volo.

Ci sono alcune librerie Perl che creano i propri modi di colmare questa limitazione in espressività, come Moose.

Perché la confusione :

A causa di pacchetti. La nostra intuizione ci dice di associare l'oggetto a un HashMap contenente la sua prototipo. Questo ci permette di creare "pacchetti" in fase di esecuzione, come può JavaScript. Perl non ha tale flessibilità (almeno non integrato, bisogna inventarla o scarica da altri moduli), e, a sua volta è ostacolato la vostra espressività runtime. Chiamarlo "benedire" non farlo molto favori nessuno dei due.

Quello che vogliamo fare :

Qualcosa di simile, ma hanno vincolante al prototipo mappa ricorsivo, e di essere implicitamente legata al prototipo, piuttosto che avere a che fare in modo esplicito.

Ecco un tentativo ingenuo a questo: il problema è che "chiamano" fareES non sa "che cosa ha chiamato", quindi potrebbe anche essere una funzione Perl universale "objectInvokeMethod (oggetto, metodo)", che verifica se l'oggetto ha il metodo o il suo prototipo ha, o il suo prototipo ha, fino a quando non raggiunge la fine e trova o no (ereditarietà prototipo). Perl ha bella magia eval per farlo ma lascio che per qualcosa che posso provare a fare in seguito.

In ogni caso ecco l'idea:

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

In ogni caso si spera che qualcuno troverà utile questo post.

I Seguendo questo pensiero per guidare lo sviluppo orientato agli oggetti Perl.

Bless associare qualsiasi riferimento struttura di dati con una classe. Dato come Perl crea la struttura di ereditarietà (in una sorta di albero) è facile da sfruttare il modello a oggetti per creare oggetti per la composizione.

Per questa associazione abbiamo chiamato oggetto, per sviluppare sempre avere in mente che lo stato interno dei comportamenti degli oggetti e di classe sono separati. E si può benedire / consentire alcun riferimento dati da utilizzare eventuali comportamenti pacchetto / classe. Dal momento che il pacchetto può capire "emotivo" stato dell'oggetto.

Ad esempio, se si può essere sicuri che qualsiasi oggetto Bug sta per essere un hash benedetta, si può (finalmente!) Compilare il codice mancante nella Bug :: metodo 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";
 }

Ora, ogni volta che il metodo print_me viene chiamato tramite un riferimento a qualsiasi hash che è stato benedetto nella classe Bug, la variabile $ self estrae il riferimento che è stato passato come primo argomento e poi le dichiarazioni di stampa accedere alle varie voci del hash benedetto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top