Pregunta

Entiendo uno utiliza la "salud" palabra clave en Perl dentro de "nuevo" método de una clase:

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

Pero, ¿qué es "bendiga" hacer a la referencia a un hash?

¿Fue útil?

Solución

En general, bless asocia un objeto con una clase.

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

Ahora, cuando se invoca un método en $object, Perl sabe cuál es el paquete para buscar el método.

Si se omite el segundo argumento, como en el ejemplo, se utiliza

el paquete / clase actual.

En aras de la claridad, el ejemplo podría escribirse de la siguiente manera:

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

EDIT: Ver Kixx es bueno contestar para un poco más de detalle.

Otros consejos

bless asocia una referencia a un paquete.

No importa lo que la referencia es a, que puede ser un hash (caso más común), a una matriz (no tan común), a un escalar (por lo general esto indica un objeto de dentro a fuera), a una expresión regular , subrutina o TYPEGLOB (ver el libro Perl: Una guía completa de los conceptos y técnicas de programación por Damian Conway de ejemplos útiles) o incluso una referencia a un identificador de archivo o directorio (caso más común).

El efecto bless-ción tiene es que permite aplicar una sintaxis especial referencia a la bendita.

Por ejemplo, si una referencia bendito se almacena en $obj (asociado por bless con el paquete "Clase"), entonces $obj->foo(@args) llamará a un foo subrutina y pasar como primer argumento el $obj referencia seguido por el resto de los argumentos (@args) . La subrutina debe definirse en "Clase" paquete. Si no hay foo subrutina en el paquete de "clase", una lista de otros paquetes (tomado forma la @ISA matriz en el paquete de "Clase") será buscado y el primer foo subrutina encontrado será llamado.

Versión corta: se marca ese resumen que se adjunta al espacio de nombres actual paquete (de modo que ese paquete proporciona la implementación de la clase)

.

Esta función indica a la entidad referenciada por REF que ahora es un objeto en el paquete CLASSNAME, o el paquete actual si se omite CLASSNAME. Se recomienda el uso de la forma de dos argumentos de bendecir.

Ejemplo :

bless REF, CLASSNAME
bless REF

Valor de retorno

Esta función devuelve la referencia a un objeto bendito en CLASSNAME.

Ejemplo :

A continuación se muestra el código de ejemplo que muestra el uso básico, la referencia al objeto es creado por la bendición de una referencia a la clase del paquete -

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

Voy a ofrecer una respuesta aquí, ya que las de aquí no acababa de hacer clic para mí.

Función de bendecir Perl asocia ninguna referencia a todas las funciones dentro de un paquete.

¿Por qué necesitamos esto?

Vamos a empezar expresando un ejemplo 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
})();

Ahora vamos a despojar el constructo clase y prescindir de él:

(() => {
    '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 función toma una tabla hash de propiedades no ordenadas (ya que no tiene sentido tener que escribir las propiedades en un orden específico en lenguajes dinámicos en 2016) y devuelve una tabla hash con esas propiedades, o si se olvidó de poner el nuevo palabra clave, devolverá todo el contexto global (por ejemplo, en la ventana del navegador o global en nodejs).

Perl no tiene "presente" ni "nueva" ni "clase", pero todavía puede tener una función que se comporta de manera similar. No vamos a tener un constructor ni un prototipo, pero vamos a ser capaces de crear nuevos animales a voluntad y modificar sus propiedades individuales.

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

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

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

Ahora, tenemos un problema: ¿Y si queremos que el animal realice los sonidos por sí mismos en lugar de nosotros imprimiendo lo que su voz es. Es decir, queremos un performSound función que imprime un sonido propio del animal.

Una forma de hacerlo es mediante la enseñanza de cada animal individual cómo hacer su sonido. Esto significa que cada gato tiene su propia función duplicado a 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'}();
})->();

Esto es malo porque performSound se pone como un nuevo objeto de función cada vez que se construye un animal. 10000 animales significa 10000 performSounds. Queremos tener una única función performSound que es utilizado por todos los animales que se ve su propio sonido y lo 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
})();

Aquí es donde la paralela a Perl detiene un poco.

nuevo operador de JavaScript no es opcional, sin él, "este" dentro de los métodos de objeto corrompe ámbito global:

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

})();

Queremos tener una función para cada animal que mira hacia arriba sonido propio de ese animal en lugar de codificar que en la construcción.

Blessing nos permite utilizar un paquete como el prototipo de los objetos. De esta manera, el objeto es consciente de la "paquete" se "hace referencia a", y a su vez puede tener las funciones en el paquete "llegar en" los casos específicos que fueron creados desde el constructor de que "objeto de paquete":

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

Resumen / TL; DR :

Perl no tiene "este", "clase", ni la "nueva". bendecir un objeto a un paquete da ese objeto una referencia al paquete, y cuando se llama a funciones en el paquete, sus argumentos será compensado por 1 ranura, y el primer argumento ($ _ [0] o cambio) será equivalente a JavaScript de "este". A su vez, se puede simular un tanto modelo de prototipo de JavaScript.

Por desgracia, hace que sea imposible (a mi entender) para crear "nuevas clases" en tiempo de ejecución, ya que necesita cada "clase" a tener su propio paquete, mientras que en javascript, no es necesario en absoluto paquetes, como " nueva" palabra clave conforma un mapa hash anónimo para su uso como un paquete en tiempo de ejecución al que se pueden añadir nuevas funciones y quitar funciones sobre la marcha.

Hay algunas bibliotecas de Perl que crean sus propias formas de salvar esta limitación en la expresividad, como alces.

¿Por qué la confusión :

Debido a paquetes. Nuestra intuición nos dice que vincular el objeto a un HashMap que contiene su prototipo. Esto nos permite crear "paquetes" en tiempo de ejecución como JavaScript lata. Perl no tiene esa flexibilidad (al menos no incorporada, hay que inventarlo o obtenerlo de otros módulos), ya su vez se ve obstaculizado su expresividad tiempo de ejecución. Que calificó de "bendecir" no hace que sea mucho más favores ninguno de ellos.

Lo que queremos hacer

Algo como esto, pero han de unión al mapa prototipo recursiva, y estar obligado implícitamente al prototipo en lugar de tener que hacerlo explícitamente.

Aquí hay un intento ingenuo en ella: el problema es que "llamar" hacerES no sabe "lo que llamó", por lo que puede ser también una función del Perl universal "objectInvokeMethod (objeto, método)" que comprueba si el objeto tiene el método, o su prototipo lo tiene, o su prototipo tiene, hasta que se llega al final y lo encuentra o no (inheritence prototípico). Perl tiene buen magia eval para hacerlo, pero voy a dejar que algo puedo intentar hacerlo más tarde.

De todos modos aquí es la 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'));
})->();

De todos modos espero que alguien encuentre este post útil.

Siguiendo este pensamiento para guiar el desarrollo orientado a objetos de Perl.

Bless asociar cualquier estructura de datos de referencia con una clase. Teniendo en cuenta lo Perl crea la estructura de herencia (en una especie de árbol) es fácil de aprovechar el modelo de objetos para crear objetos para la composición.

Para esta asociación llamamos objeto, para desarrollar siempre tiene en cuenta que el estado interno de los comportamientos de objetos y de clase están separados. Y se puede bendecir / permitir que cualquier referencia de datos para utilizar cualquier comportamiento paquete / clase. Dado que el paquete puede entender "lo emocional" estado del objeto.

Por ejemplo, si usted puede estar seguro de que cualquier objeto Bug va a ser un hash bendita, puede (por fin!) Rellene el código que falta en el Bug :: método 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";
 }

Ahora, siempre que el método print_me se llama a través de una referencia a cualquier hash que ha sido bendecido en la clase de errores, la variable $ self extrae la referencia que se pasa como primer argumento y luego las declaraciones de impresión acceder a las distintas entradas de la picadillo bendita.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top