Comment puis-je unbless un objet en Perl?
Question
De perldoc -f bénir :
bless REF,CLASSNAME
Cette fonction indique la référence par
REF
thingy qu'il est maintenant
un objet dans le package deCLASSNAME
.
Est-il possible d'obtenir une structure unblessed sans copie inutile?
La solution
unbless($ref)
Retirez le bienfait de tous les objets trouvés dans la structure de données transmis.
#!/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;
Sortie:
My : 237356 HASH : 237356
Autres conseils
données :: Structure :: Util a une fonction de unbless
qui le fera pour vous. Comme le souligne Erik sur, JSON :: XS ne sera normalement pas accepter des références bénies (bien que Je voudrais qu'il serait tout simplement ignorer et faire face à la structure de données). Il n'y a pas moyen de contourner cela dans ce cas.
Mais considérez pourquoi pensez-vous que vous devez unbless il. Est-ce que vous faites cela pour un de vos propres classes ou une autre classe? Cela ressemble étrangement à la mauvaise chose à Do. Il pourrait y avoir une meilleure façon.
Vous avez le même problème que la rupture encapsulation parce que vous devez supposer que vous savez ce que la structure interne de la référence est. Si vous allez le faire, vous pouvez simplement ignorer les choses orientée objet et accéder à la structure directement.
Si vous allez faire pour votre propre classe, envisager de fournir une méthode pour retourner une structure de données (qui ne doit pas être la structure d'origine) au lieu de changer l'objet.
Vous mentionnez dans un commentaire de suivi que vous pourriez faire cela pour contourner certains comportements de Template Toolkit. J'ai eu cette situation de deux façons selon la situation:
- Ne dépassez les données nécessaires au modèle au lieu de l'objet entier.
- Ajouter des méthodes à l'objet pour obtenir les données que vous voulez dans le modèle.
Perl est dwim, mais TT est encore DWIMmier, ce qui est regrettable parfois.
Voici un hack rapide où je définis un TO_JSON
en UNIVERSAL
il applique à tous les objets. Il fait une copie en profondeur, unblesses, et retourne la structure de données.
#!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 );
Si vous savez ce que votre objet est soutenu par, vous pouvez le faire sans utiliser les paquets.
Hash
$obj = bless {}, 'Obj';
print ref $obj, "\n";
$obj = { %$obj };
print ref $obj, "\n";
array
$obj = bless [], 'Obj';
print ref $obj , "\n";
$obj = [ @$obj ];
print ref $obj, "\n";
Scalar
$obj = bless \$a, "Obj";
print ref $obj, "\n";
$obj = \${ $$obj };
print ref $obj, "\n";
Mise à jour: Merci, Ivan! J'ai mélangé des modules. En fait, je voulais donner un lien vers Acme :: Bon sang :))
P. . S Voir aussi Acme :: Sneeze :)
P. P. S. Il n'a pas d'usage réel, c'est pourquoi il est Acme::
. Voir le poste de brian.