¿Cómo puedo deshacer un objeto en Perl?
oop bless (4)
Si sabe por qué está respaldado su objeto, puede hacerlo sin usar paquetes.
Picadillo
$obj = bless {}, ''Obj'';
print ref $obj, "/n";
$obj = { %$obj };
print ref $obj, "/n";
Formación
$obj = bless [], ''Obj'';
print ref $obj , "/n";
$obj = [ @$obj ];
print ref $obj, "/n";
Escalar
$obj = bless /$a, "Obj";
print ref $obj, "/n";
$obj = /${ $$obj };
print ref $obj, "/n";
De perldoc -f bless :
bless REF,CLASSNAME
Esta función le dice a la cosa referenciada por
REF
que es ahora
un objeto en el paqueteCLASSNAME
.
¿Hay alguna forma de obtener una estructura no autorizada sin copia innecesaria?
unbless($ref)
Elimine la bendición de cualquier objeto que se encuentre dentro de la estructura de datos aprobada.
#!/usr/bin/perl
use strict; use warnings;
use Scalar::Util qw( refaddr );
use Data::Structure::Util qw( unbless );
my $x = bless { a => 1, b => 2 } => ''My'';
printf "%s : %s/n", ref $x, refaddr $x;
unbless $x;
printf "%s : %s/n", ref $x, refaddr $x;
Salida:
My : 237356 HASH : 237356
Data::Structure::Util tiene una función no unbless
que lo hará por usted. Como señala Erik, Data::Structure::Util normalmente no aceptará referencias bendecidas (aunque desearía que simplemente lo ignore y trate con la estructura de datos). No hay forma de evitarlo en este caso.
Pero considere por qué cree que necesita deshacerlo. ¿Estás haciendo esto para una de tus clases o una clase diferente? Esto suena sospechosamente a The Wrong Thing To Do. Puede haber una mejor manera.
Tiene el mismo problema que romper la encapsulación porque debe asumir que sabe cuál es la estructura interna de la referencia. Si va a hacer eso, puede simplemente ignorar las cosas orientadas a objetos y acceder a la estructura directamente.
Si va a hacer esto para su propia clase, considere proporcionar un método para devolver una estructura de datos (que no tiene que ser la estructura original) en lugar de cambiar el objeto.
Menciona en un comentario de seguimiento que podría estar haciendo esto para evitar el comportamiento de Template Toolkit. Tuve esta situación de dos maneras dependiendo de la situación:
- Pase solo los datos que necesita a la plantilla en lugar de todo el objeto.
- Agregue métodos al objeto para obtener los datos que desea en la plantilla.
Perl es DWIM, pero TT incluso es DWIMmier, lo que a veces es desafortunado.
Aquí hay un truco rápido donde defino TO_JSON
en UNIVERSAL
para que se aplique a todos los objetos. Realiza una copia profunda, la deshace y devuelve la estructura de datos.
#!perl
use v5.10;
sub UNIVERSAL::TO_JSON {
my( $self ) = shift;
use Storable qw(dclone);
use Data::Structure::Util qw(unbless);
my $clone = unbless( dclone( $self ) );
$clone;
}
my $data = bless {
foo => bless( [], ''Local::Array'' ),
quack => bless( {
map { $_ => bless [$_, $_**2], ''Local::Array'' }
grep { is_prime } 1 .. 10
}, ''Local::Hash'' ),
}, ''Local::Hash'';
use JSON::XS;
my $jsonner = JSON::XS->new->pretty->convert_blessed(1);
say $jsonner->encode( $data );
Acme::Curse :)
Actualización: ¡ Gracias, Ivan! Mezclé módulos. En realidad, quería dar un enlace a Acme::Damn :))
PD Vea también Acme::Sneeze :)
PPS No tiene uso real, es por eso que es Acme::
. Ver la publicación de Brian.