2010-10-01 2 views
5

Je suis un débutant absolu à Moose et jusqu'à présent, j'ai lu Moose et la plupart des Cookbook.Comment puis-je accéder aux attributs en lecture seule des objets Moose?

Il y a quelques choses que je ne comprends pas. J'ai créé le package suivant:

package MyRange; 

use Moose; 
use namespace::autoclean; 

has [ 'start', 'end' ] => (
    is  => 'ro', 
    isa  => 'Int', 
    required => 1, 
); 

__PACKAGE__->meta->make_immutable; 

1; 

Puis:

use MyRange;  
my $br = MyRange->new(
    start    => 100, 
    end     => 180 
); 

Maintenant, je peux accéder à mes champs en utilisant par exemple $br->{start}, mais je peux également les modifier (bien qu'ils ne soient "en lecture seule") en utilisant par ex. $br->{start}=5000. Je peux également ajouter de nouvelles clés comme $br->{xxx}=111.

Est-ce que je manque quelque chose? L'objet n'est-il pas protégé d'une manière ou d'une autre? Quelle est la signification de ro?

Répondre

14

Lorsque vous avez indiqué is => 'ro', vous avez demandé à Moose de créer des accesseurs en lecture seule pour vous, c'est-à-dire une méthode de lecture. Vous appelez ça comme

$br->start; 

ou

$br->end; 

Définition des attributs en utilisant ces méthodes se traduira par une exception:

$br->start(42); 

Si vous aviez utilisé is => 'rw', le serait au-dessus de travail et mettre à jour la valeur de l'attribut.

Ce que vous faites est un accès direct au hachage sur l'objet, qui viole l'encapsulation et ne devrait jamais être nécessaire lorsque vous utilisez Moose.

Le manuel Moose, c'est-à-dire tous les documents sous l'espace de noms Moose::Manual, explique cela en détail. Un bon point de départ pour des questions comme celle-ci est probablement Moose::Manual::Attributes.

+0

+1 Merci! Un suivi, si je peux: J'ai quelques champs qui ne sont pas requis. Si elles ne sont pas définies, et j'essaie d'accéder à ces valeurs 'undef' je voudrais obtenir une erreur. Dois-je définir un lecteur pour chacun d'eux? Ou peut-être utiliser un sous-type 'die' dans' default'? –

+1

Vous voudrez peut-être créer une nouvelle question pour une réponse plus détaillée, mais: Avez-vous un design où les valeurs ne sont pas requises initialement, mais l'utilisateur est autorisé à les remplir plus tard en utilisant des méthodes d'écriture et doit le faire avant d'appeler une fonctionnalité qui l'utilise? La plupart du temps, vous devriez probablement y repenser votre design, mais dans les rares cas où cela a du sens, mon extension 'MooseX :: LazyRequire' pourrait être utile.Tout ce que fait est de faire un attribut requis, mais en reportant l'exception du temps de construction au moment où l'attr est accessible. – rafl

+0

Notez également que vous pouvez demander à Moose de générer des méthodes 'predicate' pour vous. Ceux que vous pouvez utiliser pour vérifier explicitement si une valeur a été définie pour un attribut par l'intermédiaire des méthodes constructor ou writer. Ceci est particulièrement pratique pour les attributs qui ne sont pas requis et pour lesquels 'undef' est une valeur valide. – rafl

3

Lorsque vous accédez à l'attribut avec $br->{start}, vous contournez l'accesseur et vous adressez directement l'implémentation de Moose sous-jacente. Vous pouvez le faire, mais vous n'êtes pas censé le faire. En outre, si Moose modifie l'implémentation, votre code va se casser.

Vous devriez plutôt accéder à l'attribut en utilisant la méthode accesseur:

my $start = $br->start; 

Quand vous dites que l'attribut est « RO », cela signifie que vous n'êtes pas autorisé à modifier la valeur d'attribut en utilisant l'accesseur:

$br->start(32); 
Questions connexes