2017-05-19 7 views
0

Perl: objet récursif instanciation avec Moose

Dans le code exemple ci-dessous, je définition d'une classe Person qui peut avoir des objets enfants de la même classe.

Quand j'invoque la méthode printTree, j'attends la sortie suivante

Sam Ram Geeta 

Ce que je vois au lieu est

SamRamRamRamRamRamRamRamRamRamRamR..... 

Tous les conseils sur ce que je fais mal et comment atteindre mon objectif ?

package Person; 

use Moose; 

has name => (is => 'ro'); 

my @kids; 

sub addChild { 
    my ($self, $name) = @_; 
    my $k = Person->new(name => $name); 
    push @kids, $k; 
    return $k; 
} 

sub printTree { 
    my $self = shift; 
    print $self->name; 
    $_->printTree foreach (@kids); 
} 



no Moose; 

package main; 

my $s = Person->new(name => "Sam"); 
my $r = $s->addChild("Ram"); 
my $g = $s->addChild("Geeta"); 

$s->printTree; 
+1

. Btw, ne devrait pas '@ enfants 'aussi être une propriété? –

+3

Votre '@ kids' est un singleton dans la classe. Cela signifie que tous les objets le partagent. C'est une mauvaise idée. Ça devrait être une propriété. Je vais écrire une réponse plus tard. – simbabque

Répondre

6

Le problème est que @Person::kids ne pas appartenir à une instance, et vous finissez efficacement avec

@Person::kids = ($r, $g); 
$s->printTree() loops through @Person::kids, calls 
$r->printTree() loops through @Person::kids, calls 
    $r->printTree() loops through @Person::kids, calls 
    $r->printTree() loops through @Person::kids, calls 
    ... 

Vous devez faire un attribut, par exemple

has kids => (
    isa => 'ArrayRef[Person]', 
    traits => ['Array'], 
    handles => { 
     all_kids => 'elements', 
     push_kids => 'push', 
    }, 
    default => sub { [] }, 
); 
sub addChild { 
    my ($self, $name) = @_; 
    my $k = Person->new(name => $name); 
    $self->push_kids($k); 
    return $k; 
} 
sub printTree { 
    my ($self) = @_; 
    print $self->name; 
    $_->printTree foreach $self->all_kids; 
} 

Vous pouvez vérifier perldoc Moose::Meta::Attribute::Native::Trait::Array pour d'autres poignées utiles du trait Array. N'appelez `printTree` dans` printTree` que dans le champ