2009-01-08 5 views
4

Je préfère le faire:Existe-t-il un andand pour Perl?

say $shop->ShopperDueDate->andand->day_name(); 

par rapport à ceci:

say $shop->ShopperDueDate->day_name() if $shop->ShopperDueDate; 

Toutes les idées?

(. Cette idée est inspirée par l'extension Ruby andand)

(En fait, il est inspiré par le langage Groovy, mais la plupart des gens ne savent pas que ;-)

mise à jour: I pense que les deux peut-être() et eval {} sont de bonnes solutions. Ce n'est pas ruby ​​donc je ne peux pas m'attendre à lire toutes les méthodes/fonctions de gauche à droite de toute façon, alors peut-être pourrait-être une aide. Et puis eval eval est vraiment la façon perl de le faire.

+0

Vous avez également posté ceci à Perlmonks (http://www.perlmonks.org/index.pl?node_id=734774). Veuillez informer les gens lorsque vous postez la même question à plusieurs endroits afin que les gens puissent voir toutes les réponses et ne pas perdre de temps à répondre lorsque vous avez votre réponse. –

Répondre

4

Je pense que je viens de l'écrire. Je viens de le télécharger sur CPAN, vous pouvez le trouver here.

+0

Pouvez-vous développer sur "vous ne pouvez pas appeler des méthodes sur des valeurs indéfinies"? Je ne suis pas complètement sûr de lire tout mon article. – ysth

+0

Les valeurs non définies ne peuvent pas être des références bénies et, par conséquent, vous ne pouvez pas appeler de méthodes sur celles-ci. Il faut un peu de magie pour faire ce travail. –

9

Vous pouvez utiliser la déclaration eval de Perl pour intercepter des exceptions, y compris ceux d'essayer d'appeler des méthodes sur un argument non défini:

eval { 
    say $shop->ShopperDueDate->day_name(); 
}; 

Depuis eval renvoie la dernière déclaration évaluée, ou undef en cas d'échec, vous pouvez enregistrer la nom du jour dans une variable comme ceci:

my $day_name = eval { $shop->ShopperDueDate->day_name(); }; 

Si vous souhaitez réellement inspecter l'exception, vous pouvez regarder dans la variable spéciale [email protected]. Ce sera généralement une simple chaîne pour les exceptions intégrées de Perl, mais peut être un objet d'exception complète si l'exception provient de autodie ou d'un autre code qui utilise des exceptions d'objet.

eval { 
    say $shop->ShopperDueDate->day_name(); 
}; 

if ([email protected]) { 
    say "The error was: [email protected]"; 
} 

Il est aussi possible d'enchaîner une séquence de commandes au moyen d'un bloc eval. Ce qui suit ne vérifiera pour voir si c'est un week-end à condition que nous n'avons eu aucune exception levée en levant $day_name.

eval { 
    my $day_name = $shop->ShopperDueDate->day_name(); 

    if ($day_name ~~ [ 'Saturday', 'Sunday' ]) { 
     say "I like weekends"; 
    } 
}; 

Vous pouvez penser eval comme étant le même que try d'autres langues; en effet, si vous utilisez le module Error du CPAN, vous pouvez même l'épeler try. Il est également intéressant de noter que la forme de bloc d'eval (que j'ai montrée ci-dessus) ne vient pas avec des pénalités de performance, et est compilé avec le reste de votre code. La forme de corde de eval (que je n'ai pas montrée) est une bête différente entièrement, et devrait être employée avec parcimonie, si du tout. Techniquement considéré comme une déclaration en Perl, et est donc l'un des rares endroits où vous verrez un point-virgule à la fin d'un bloc. Il est facile de les oublier si vous n'utilisez pas eval régulièrement.

Paul

9

Je suppose que votre deuxième exemple devrait être mieux:

say $shop->ShopperDueDate ? $shop->ShopperDueDate->day_name() : undef; 

au lieu de ce qu'il dit réellement.

Quoi qu'il en soit, vous ne pouvez pas le faire avec exactement cette syntaxe sans filtre source, car undef est pas un objet, mais un opérateur unaire, donc il ne peut pas avoir des méthodes.

Au lieu de cela, considérez ceci:

package noop; 
our $maybe = bless [], 'noop'; 
sub AUTOLOAD { undef }; 

Ce $noop::maybe est un objet; toutes ses méthodes renvoient cependant undef. Par ailleurs, vous aurez une fonction régulière comme ceci:

sub maybe { $_[0] || $noop::maybe; } 

alors vous pouvez écrire ceci:

say maybe($shop->ShopperDueDate)->day_name() 

Cela fonctionne parce que « peut-être » retours retourne son argument si elle est vraie, sinon il retourne notre $noop::maybe objet qui a des méthodes qui retournent toujours undef.

EDIT: Correction! la ->andand-> syntaxe peut être être eu sans un filtre de source, en utilisant un XS qui bouge avec les internes de Perl. Leon Timmermans fait une implémentation qui prend cette route. Il remplace la fonction undef() globalement, il est donc probable qu'il soit beaucoup plus lent que ma méthode.

+0

Pourquoi dites-vous que ce serait mieux? C'est exactement le même droit? –

+0

L'ordre de les lire a un peu plus de sens dans son exemple, IMHO –

+0

Frew: Le premier exemple est say ($ some_value) où le second exemple est à peu près équivalent à if ($ some_value) {say ($ some_value)} - le l'ancien exemple a toujours dit() étant appelé, alors que le dernier rend l'appel say() conditionnel. – geocar

0

Quelque chose comme (non testé):

use Object::Generic::False; 
sub UNIVERSAL::andand { $_[0] || Object::Generic::False->false } 

UNIVERSAL est automatiquement une sous-classe de toutes les autres classes, donc cela donne etet pour tous les objets. (Il est évident que la création de méthodes dans UNIVERSAL présente un risque de conflit ou d'action surprenante à distance, donc il ne doit pas être utilisé de manière imprudente.) Si l'objet sur lequel la méthode andand est appelée est vrai, retournez-le; sinon retourner un objet faux générique qui se retourne pour tout appel de méthode utilisé sur celui-ci.

+0

Le problème avec ceci est que vous ne pouvez pas appeler des méthodes sur des valeurs indéfinies. –

+0

Si vous le souhaitez, vous pouvez toujours utiliser le pragma Autobox pour promouvoir la valeur indéfinie à un objet de première classe. Ensuite, vous pouvez * appeler * des méthodes dessus. ;) – pjf

+0

Je l'ai déjà fait, voir ma propre réponse à ce post ;-) –

Questions connexes