Gotchas communs pour Perl? [fermé]

la question sur caractéristiques cachées de Perl a donné au moins une réponse qui pourrait être considérée comme une caractéristique ou une caractéristique erronée. Il a semblé logique de donner suite à cette question: Quelles sont les erreurs non évidentes courantes en Perl? Des choses qui semblent devoir marcher, mais qui ne le font pas.

Je ne vais pas donner de directives sur la façon de structurer les réponses, ou ce qui est "trop facile" pour être considéré comme un gotcha, puisque c'est ce que le vote est pour.

Table des réponses

syntaxe

Sémantique / Caractéristiques Linguistiques

débogage

"Meilleures Pratiques

Méta-Réponses

Voir aussi: ASP.NET - gotchas commun

75
demandé sur Adam Bellaire 2008-10-03 16:50:08

29 réponses

Le fait que les guillemets simples peuvent être utilisés pour remplacer :: dans les identificateurs.

prendre en considération:

use strict;
print "$foo";        #-- Won't compile under use strict
print "$foo's fun!"; #-- Compiles just fine, refers to $foo::s

conduisant au problème suivant:

use strict;
my $name = "John";
print "$name's name is '$name'";
# prints:
#  name is 'John'

le moyen recommandé pour éviter cela est d'utiliser des bretelles autour de votre nom de variable:

print "${name}'s name is '$name'";
# John's name is 'John'

et aussi à use warnings , car il vous parlera de l'utilisation de la variable non définie $name::s

38
répondu Adam Bellaire 2009-02-13 12:20:47

vous pouvez imprimer sur une manchette lexicale: bon.

print $out "hello, world\n";

vous réalisez alors qu'il pourrait être agréable d'avoir un hash de filehandles:

my %out;
open $out{ok},   '>', 'ok.txt' or die "Could not open ok.txt for output: $!";
open $out{fail}, '>', 'fail.txt' or die "Could not open fail.txt for output: $!";

jusqu'ici, tout va bien. Maintenant, essayez de les utiliser, et imprimez à l'un ou l'autre selon une condition:

my $where = (frobnitz() == 10) ? 'ok' : 'fail';

print $out{$where} "it worked!\n"; # it didn't: compile time error

vous devez envelopper la déréférence de hachage dans une paire de boucles:

print {$out{$where}} "it worked!\n"; # now it did

c'est un comportement totalement non intuitif. Si vous Je n'ai pas entendu parler de ça, ni lu la documentation.je doute que tu puisses le découvrir par toi-même.

28
répondu dland 2008-10-03 14:25:00

c'est une méta-réponse. Beaucoup de mauvais gotchas sont attrapés par Perl::Critic , que vous pouvez installer et exécuter à partir de la ligne de commande avec la commande perlcritic , ou (si vous êtes heureux d'envoyer votre code sur Internet, et ne pas être en mesure de personnaliser vos options) via le Perl::Critic website .

Perl::Critic fournit également des références à Damian Conways Perl Best Pratiques Livre, y compris les numéros de page. Donc, si vous êtes trop paresseux pour lire le livre entier, Perl::Critic peut encore vous dire les bits que vous devrait lire.

27
répondu pjf 2008-10-04 00:45:50

Perl DWIMmer luttes avec << (ici-document) la notation lors de l'utilisation de print avec lexicale descripteurs:

# here-doc
print $fh <<EOT;
foo
EOT

# here-doc, no interpolation
print $fh <<'EOT';
foo
EOT

# bitshift, syntax error
# Bareword "EOT" not allowed while "strict subs" in use
print $fh<<EOT;
foo
EOT

# bitshift, fatal error
# Argument "EOT" isn't numeric...
# Can't locate object method "foo" via package "EOT"...
print $fh<<'EOT';
foo
EOT

la solution est soit de faire attention à inclure des espaces blancs entre le filehandle et le << ou de désambiguer le filehandle en l'enveloppant dans {} bretelles:

print {$fh}<<EOT;
foo
EOT
18
répondu Michael Carman 2008-10-03 15:11:11

la page de manuel perltrap répertorie de nombreux pièges pour les non avertis organisés par type.

17
répondu Michael Carman 2008-10-03 21:06:02

le gotcha le plus commun est de démarrer vos fichiers avec quelque chose de différent de

use strict;
use diagnostics;

PJF ajoute: soyez averti que les diagnostics ont un impact significatif sur la performance. Il ralentit le démarrage du programme, il doit charger perldiag.pod, et jusqu'à bleadperl dès Il ya quelques semaines, il ralentit et gonfle regexps parce qu'il utilise $&. Il est recommandé d'utiliser les avertissements et d'exécuter splain sur les résultats.

16
répondu Vinko Vrsalovic 2017-05-23 11:55:01

assigner des tableaux à des scalaires n'a aucun sens pour moi. Par exemple:

$foo = ( 'a', 'b', 'c' );

assigne ' c ' à $foo et jette le reste du tableau. Celui-ci est plus bizarre:

@foo = ( 'a', 'b', 'c' );
$foo = @foo;

cela ressemble à cela devrait faire la même chose que le premier exemple, mais au lieu de cela il place $foo à la longueur de @foo , donc $foo == 3 .

15
répondu Graeme Perrow 2008-10-03 12:59:04

"mon" déclarations doivent utiliser des parenthèses autour de listes de variables

use strict;
my $a = 1;
mysub();
print "a is $a\n";

sub {
    my $b, $a;   # Gotcha!
    $a = 2;
}

imprime 2 parce que le my déclaration applique uniquement aux $b (la mention de $a sur cette ligne n'a tout simplement pas faire quelque chose). Notez que cela se produit sans avertissement même lorsque "use strict" est en vigueur.

ajouter "utiliser des avertissements" (ou le drapeau-w) améliore grandement les choses avec Perl dire parenthèses absentes autour de" ma "liste . Cela montre, comme beaucoup l'ont déjà fait, pourquoi le pragmatisme strict et les avertissements sont toujours une bonne idée.

15
répondu andy 2012-06-16 06:13:46

Utilisation de la valeur non initialisée dans la concaténation...

celui-ci me rend fou. Vous avez une impression qui inclut un certain nombre de variables, comme:

print "$label: $field1, $field2, $field3\n";

et l'une des variables est undef . Vous considérez cela comme un bug dans votre programme -- c'est pourquoi vous utilisiez le "strict" pragma. Peut-être votre schéma de base de données permettait NULL dans un champ auquel vous ne vous attendiez pas, ou vous avez oublié d'initialiser une variable, etc. Mais tous les un message d'erreur vous indique qu'une valeur non initialisée a été rencontrée lors d'une opération de concaténation ( . ). Si seulement il vous a dit le nom de la variable qui a été uninitialized!

puisque Perl ne veut pas imprimer le nom de la variable dans le message d'erreur pour une raison quelconque, vous finissez par le traquer en définissant un point de rupture (pour regarder quelle variable est undef ), ou en ajoutant du code pour vérifier la condition. Très agaçant quand ça n'arrive qu'une fois sur des milliers dans un script CGI et que vous ne pouvez pas le recréer facilement.

15
répondu andy 2012-06-16 06:14:56

Confusion des références et des objets réels:

$a = [1,2,3,4];
print $a[0];

(Il devrait être l'un des $a->[0] (best), $$a[0] , @{$a}[0] ou @$a[0] )

15
répondu Vinko Vrsalovic 2015-05-13 14:06:18

la plupart des opérateurs de boucle de Perl ( foreach , map , grep ) localisez automatiquement $_ mais while(<FH>) ne le fait pas. Cela peut conduire à des actions étranges-à-distance.

14
répondu Michael Carman 2008-10-06 14:03:06

je l'ai fait une fois:

my $object = new Some::Random::Class->new;

m'a Pris âges pour trouver l'erreur. La syntaxe de la méthode indirecte est eeevil .

12
répondu Dan 2008-10-03 15:26:02
my $x = <>;
do { 
    next if $x !~ /TODO\s*[:-]/;
    ...
} while ( $x );

do n'est pas une boucle. Vous ne pouvez pas next . C'est une instruction pour effectuer un bloc. C'est la même chose que

$inc++ while <>;

malgré qu'il ressemble à une construction dans la famille C des langues.

11
répondu Axeman 2015-08-07 14:43:55
Les constantes

peuvent être redéfinies. Une façon simple de accidentellement redéfinir une constante est de définir une constante comme une référence.

 use constant FOO => { bar => 1 };
 ...
 my $hash = FOO;
 ...
 $hash->{bar} = 2;

Maintenant FOO {bar => 2};

si vous utilisez mod_perl (au moins en 1.3), la nouvelle valeur FOO persistera jusqu'à ce que le module soit mis à jour.

9
répondu cwhite 2008-10-03 23:57:55

Unaire moins avec "foo" crée "-foo" :

perl -le 'print -"foo" eq "-foo" ? "true" : "false"'

Cela ne fonctionne que si le premier caractère correspond à /[_a-zA-Z]/ . Si le premier caractère est un "-" alors il modifie le premier caractère d'un "+" , et si le premier caractère est un "+" alors il modifie le premier caractère d'un "-" . Si le premier caractère correspond à /[^-+_a-zA-Z]/ puis il tente de convertir la chaîne en nombre et nie le résultat.

perl -le '
    print -"foo";
    print -"-foo";
    print -"+foo";
    print -"\x{e9}"; #e acute is not in the accepted range
    print -"5foo";   #same thing for 5
'

le code ci-dessus imprime

-foo
+foo
-foo
-0
-5

cette fonctionnalité existe surtout pour permettre aux gens de dire des choses comme

my %options = (
    -depth  => 5,
    -width  => 2,
    -height => 3,
);
8
répondu Chas. Owens 2009-09-03 14:09:12

Cette chasse aux sorcières est fixé en Perl 5.10 - si vous êtes assez chanceux pour travailler quelque part qui n'est pas allergique à la mise à niveau des choses >:-(

je parle de la Variable qui est valablement Zéro. vous savez, celui qui provoque des résultats inattendus dans des clauses comme:

unless ($x) { ... }
$x ||= do { ... };

Perl 5.10 A l'opérateur //= ou défini-ou .

c'est particulièrement insidieux quand le zéro valide est causé par un État de bord qui n'a pas été pris en compte dans les tests avant que votre code ne soit mis en production...

8
répondu RET 2012-06-16 06:11:02

quelles valeurs prévoyez-vous que @ _ contienne dans le scénario suivant?

sub foo { } 

# empty subroutine called in parameters

bar( foo(), "The second parameter." ) ;

je m'attends à recevoir dans bar :

undef, "The second parameter." 

mais @ _ contient seulement le second paramètre, au moins lors d'un essai avec perl 5.88.

7
répondu 2008-10-06 17:06:03

utilisant le modificateur /o avec un motif regex stocké dans une variable.

m/$pattern/o

spécifier /o est une promesse que $pattern ne changera pas. Perl est assez intelligent pour reconnaître si oui ou non il a changé et recompiler le regex conditionnellement, donc il n'y a plus de bonne raison d'utiliser /o . Alternativement, vous pouvez utiliser qr// (par exemple si vous êtes obsédé par le fait d'éviter le chèque).

6
répondu Michael Carman 2008-10-03 20:40:30

la réponse de Graeme Perrow était bonne, mais elle est encore meilleure!

étant donné une fonction typique qui renvoie une belle liste dans le contexte d'une liste, vous pourriez bien vous demander: Qu'est-ce qu'elle retournera dans le contexte scalaire? (Par "typique", je veux dire le cas commun dans lequel la documentation ne dit pas, et nous supposons qu'il n'utilise aucune wantarray Drôle d'affaire. C'est peut-être une fonction que vous avez écrite vous-même.)

sub f { return ('a', 'b', 'c'); }
sub g { my @x = ('a', 'b', 'c'); return @x; }

my $x = f();           # $x is now 'c'
my $y = g();           # $y is now 3

le contexte une fonction appelée est propagée dans les instructions return de cette fonction.

je suppose que l'appelant avait tort de vouloir une simple règle empirique pour permettre un raisonnement efficace sur le comportement code . Vous avez raison, Perl, il est préférable pour le personnage de l'appelant à ramper à travers le code source de la fonction appelée à chaque fois .

6
répondu j_random_hacker 2017-05-23 10:31:39

comparant les cordes en utilisant == et != au lieu de eq et ne . Par exemple:

$x = "abc";
if ($x == "abc") {
    # do something
}

au lieu de:

$x = "abc";
if ($x eq "abc") {
    # do something
}
6
répondu Nathan Fellman 2009-12-06 12:40:18

Que pensez-vous du fait que

@array = split( / /, $string );

ne donne pas le même résultat que

@array = split( ' ', $string );

si $ string a des espaces principaux?

qui pourrait surprendre certaines personnes.

6
répondu AmbroseChapel 2011-07-12 06:02:26

vous ne pouvez pas localiser les variables exportées à moins d'exporter la totalité de typeglob.

5
répondu Michael Carman 2008-10-03 13:15:12

Si vous êtes assez stupide pour le faire Perl vous permettra de déclarer plusieurs variables avec le même nom:

my ($x, @x, %x);

parce que Perl utilise des sigles pour identifier context plutôt que la variable type , cela garantit presque la confusion quand le code plus tard utilise les variables, en particulier si $x est une référence:

$x[0]
$x{key}
$x->[0]
$x->{key}
@x[0,1]
@x{'foo', 'bar'}
@$x[0,1]
@$x{'foo', 'bar'}
...
4
répondu Michael Carman 2008-10-03 15:24:58

ajouter des parenthèses supplémentaires ne pourrait jamais changer le sens du code , Non? Droit?

my @x = ( "A"  x 5 );      # @x contains 1 element, "AAAAA"
my @y = (("A") x 5 );      # @y contains 5 elements: "A", "A", "A", "A", "A"

oh, c'est vrai, C'est Perl.

EDIT: pour faire bonne mesure, si x est appelée dans un contexte scalaire, puis les parenthèses n'a pas d'importance, après tout:

my $z = ( "A"  x 5 );      # $z contains "AAAAA"
my $w = (("A") x 5 );      # $w contains "AAAAA" too

Intuitive.

4
répondu j_random_hacker 2009-02-15 13:34:38

oubliant de préparer le chemin du répertoire aux résultats de readdir avant de faire des tests sur ces résultats. Voici un exemple:

#!/usr/bin/env perl
use strict;
use warnings;

opendir my $dh, '/path/to/directory/of/interest'
  or die "Can't open '/path/to/directory/of/interest for reading: [$!]";

my @files = readdir $dh; # Bad in many cases; see below
# my @files = map { "/path/to/directory/of/interest/$_" } readdir $dh;

closedir $dh or die "Can't close /path/to/directory/of/interest: [$!]";

for my $item (@files) {
  print "File: $item\n" if -f $item;
  # Nothing happens. No files? That's odd...
}

# Scratching head...let's see...
use Data::Dumper;
print Dumper @files;
# Whoops, there it is...

Cette chasse aux sorcières est mentionné dans la documentation de la readdir , mais je pense que c'est encore une erreur assez commune.

3
répondu Telemachus 2009-06-24 10:05:05

hachage "constructeur" n'est rien de plus qu'une liste, et la => fat virgule est rien de plus que du sucre syntaxique. Vous pouvez vous faire mordre par ceci en confondant la syntaxe [] avec la syntaxe () de la liste:

my %var = (
    ("bar", "baz"),
    fred => "barney",
    foo => (42, 95, 22)
);

# result
{ 'bar' => 'baz',
  '95' => 22,
  'foo' => 42,
  'fred' => 'barney' };

# wanted
{ 'foo' => [ 42, 95, 22 ] }
1
répondu hhaamu 2011-08-15 17:16:46

fautes d'Orthographe dans les noms de variables ... Une fois, j'ai passé un après-midi entier à résoudre un code qui ne se comportait pas correctement seulement pour trouver une faute de frappe sur un nom de variable, ce qui n'est pas une erreur dans Perl, mais plutôt la déclaration d'une nouvelle variable.

-1
répondu paxos1977 2008-10-04 00:08:24

modifiant le tableau sur lequel vous faites une boucle dans un pour(chacun) comme dans:

my @array = qw/a b c d e f g h/;

for ( @array ) {
    my $val = shift @array;
    print $val, "\n";
}

il devient confus et ne fait pas ce que vous attendez

-2
répondu Matteo Riva 2010-01-06 20:08:19

traiter un scalaire comme un entier:

$n = 1729;
$s = 0;
$i = 0;

while ($n) {
    $s += $n % 10;
    $n/=10;
    $i ++
}

print "Sum : $s\n";
print "Number of iterations : $i\n"

somme: 19

nombre d'itérations : 327

Idéalement, il devrait avoir eu seulement quatre itérations, mais un scalaire n'est pas un int, et nous avons obtenu un résultat inattendu.

-2
répondu Balbir Singh 2012-06-16 06:16:49