Question

Je comprends l'on utilise la méthode « bless » mot-clé en Perl intérieur « nouveau » d'une classe:

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

Mais ce qui est « bénir » faire exactement à cette référence de hachage?

Était-ce utile?

La solution

En général, bless associe un objet à une classe.

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

Maintenant, quand vous invoquez une méthode sur $object, Perl savoir quel paquet pour rechercher la méthode.

Si le second argument est omis, comme dans votre exemple, le package en cours / classe est utilisée.

Par souci de clarté, votre exemple peut être écrit comme suit:

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

EDIT: Voir KIXX d 'un bon Réponse un peu plus en détail.

Autres conseils

bless associe une référence à un paquet.

Peu importe ce que la référence est, il peut être un hachage (cas le plus fréquent), à un scalaire (généralement à un tableau (pas si commun) cela indique un objet inside-out ), à une expression régulière , sous-routine ou typeglob (voir le Perl orienté objet: Guide complet des concepts et techniques de programmation par Damian Conway des exemples utiles) ou même une référence à un fichier ou répertoire poignée (cas moins fréquent).

Le bless-ing effet a est qu'il vous permet d'appliquer une syntaxe spéciale à la référence bénie.

Par exemple, si une référence bénie est stockée dans $obj (associé par bless avec le paquet « classe »), puis $obj->foo(@args) convoquera une foo de sous-programme et passer comme premier argument le $obj de référence suivi par le reste des arguments (@args) . Le sous-programme doit être défini dans le paquet « classe ». S'il n'y a pas foo de sous-programme dans le paquet « classe », une liste d'autres paquets (pris forme le @ISA de tableau dans le paquet « classe ») sera recherchée et la première foo de sous-programme trouvé sera appelé.

Version courte: il est marquage de hachage comme attaché à l'espace de noms de package en cours (de sorte que ce paquet fournit la mise en œuvre de la classe)

.

Cette fonction indique à l'entité référencée par REF qu'elle est maintenant un objet dans le package NOMCLASSE ou le paquetage courant si CLASSNAME est omis. L'utilisation de la forme à deux arguments de bless est recommandé.

Exemple :

bless REF, CLASSNAME
bless REF

Valeur de retour

Cette fonction retourne la référence à un objet dans la chance CLASSNAME.

Exemple :

Voici le code exemple montrant son utilisation de base, la référence d'objet est créé par la bénédiction d'une référence à la classe du paquet -

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

Je vais vous donner une réponse ici puisque ceux ici ne sont pas tout à fait cliquer pour moi.

fonction de bénir Perl associe toute référence à toutes les fonctions à l'intérieur d'un paquet.

Pourquoi aurions-nous besoin?

Commençons par l'expression d'un exemple en 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
})();

permet maintenant la bande loin structure de classe et de faire faire sans elle:

(() => {
    '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 fonction prend une table de hachage des propriétés non ordonnées (car il n'a pas de sens d'avoir à écrire des propriétés dans un ordre spécifique dans les langages dynamiques en 2016) et renvoie une table de hachage avec ces propriétés, ou si vous avez oublié de mettre la nouvelle mot-clé, il retournera tout le contexte global (par exemple la fenêtre dans le navigateur ou mondiale nodejs).

Perl n'a pas de « ce » ni « nouvelle », ni « classe », mais il peut encore avoir une fonction qui se comporte de la même. Nous n'avons un constructeur ni un prototype, mais nous serons en mesure de créer de nouveaux animaux à volonté et modifier leurs propriétés individuelles.

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

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

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

Maintenant, nous avons un problème: si nous voulons que l'animal d'avoir les sons eux-mêmes au lieu de nous l'impression que leur voix est. Autrement dit, nous voulons une performSound fonction qui imprime son propre de l'animal.

Une façon de le faire est d'enseigner chaque animal comment faire son son. Cela signifie que chaque chat a sa propre fonction double à 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'}();
})->();

Ceci est mauvais car performSound est mis comme un objet de toute nouvelle fonction à chaque fois qu'un animal est construit. 10000 animaux signifie 10000 performSounds. Nous voulons avoir une performSound seule fonction qui est utilisée par tous les animaux qui recherche leur propre son et l'imprime.

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

Voici où le parallèle à Perl arrête un peu.

nouvel opérateur de JavaScript n'est pas en option, sans elle, « ce » à l'intérieur des méthodes d'objet corrompt portée 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.

})();

Nous voulons avoir une fonction pour chaque animal qui recherche son propre plutôt que de coder en dur à la construction de cet animal.

Blessing nous permet d'utiliser un paquet comme le prototype des objets. De cette façon, l'objet est au courant du « paquet » il est « référencé », et à son tour, peut avoir les fonctions dans le paquet « atteindre dans » les cas spécifiques qui ont été créés à partir du constructeur de ce « objet package »:

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

Résumé / TL; DR :

Perl n'a pas de "ce", "classe", ni "nouvelle". bénissant un objet à un paquet donne l'objet d'une référence à l'emballage, et lors de l'appel des fonctions dans le paquet, leurs arguments sera compensée par une fente, et le premier argument ($ _ [0] ou décalage) sera équivalent à javascript "this" de. À son tour, vous pouvez simuler un peu le modèle prototype de JavaScript.

Malheureusement, il rend impossible (à ma connaissance) de créer des « nouvelles classes » lors de l'exécution, que vous avez besoin chaque « classe » d'avoir son propre paquet, alors qu'en javascript, vous n'avez pas besoin de paquets du tout, comme " nouveau » mot-clé représente un hashmap anonyme pour vous d'utiliser comme un package à l'exécution auquel vous pouvez ajouter de nouvelles fonctions et de supprimer des fonctions à la volée.

Il y a quelques bibliothèques Perl créant leurs propres moyens de combler cette limitation dans l'expressivité, tels que Moose.

Pourquoi la confusion :

En raison de paquets. Notre intuition nous dit de lier l'objet à un hashmap contenant son prototype. Cela nous permet de créer des « packages » à l'exécution comme peut JavaScript. Perl n'a pas une telle flexibilité (du moins pas intégré, il faut inventer ou obtenir d'autres modules), et à son tour votre expressivité d'exécution est entravée. L'appeler « bénir » ne le fait pas beaucoup de faveurs ni.

Ce que nous voulons faire :

Quelque chose comme ça, mais qui ont la liaison à la carte prototype récursive, et d'être lié implicitement au prototype plutôt que d'avoir à faire explicitement.

Voici une tentative naïve: le problème est que « appeler » fairees sait pas « ce qui l'a appelé », il peut aussi bien être une fonction perl universelle « objectInvokeMethod (objet, méthode) » qui vérifie si l'objet a la méthode, ou son prototype a, ou son prototype a, jusqu'à ce atteint la fin et trouve ou non (prototypique inheritence). Perl a une belle magie eval pour le faire, mais je vais laisser cela pour quelque chose que je peux essayer de faire plus tard.

est ici tout cas l'idée:

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

Quoi qu'il en soit, espérons que quelqu'un va trouver ce poste utile.

Je Suite à cette pensée pour guider le développement orienté objet Perl.

Bless associer toute référence de structure de données avec une classe. Étant donné la façon dont Perl crée la structure d'héritage (dans une sorte d'arbre), il est facile de tirer parti du modèle d'objet pour créer des objets pour la composition.

Pour cette association nous avons appelé objet, à développer ont toujours à l'esprit que l'état interne des comportements d'objet et de classe sont séparés. Et vous pouvez bénir / autoriser toute référence de données à utiliser des comportements package / classe. Étant donné que le paquet peut comprendre « l'émotionnel » état de l'objet.

Par exemple, si vous pouvez être sûr que tout objet Bug va être un hachage béni, vous pouvez (enfin!) Remplir le code manquant dans la méthode 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";
 }

Maintenant, chaque fois que la méthode print_me est appelée par une référence à un hachage qui a été béni dans la classe Bug, la variable $ self extrait la référence qui a été adopté comme premier argument et les déclarations d'impression d'accéder aux différentes entrées de la hachage béni.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top