FAQ PerlConsultez toutes les FAQ
Nombre d'auteurs : 18, nombre de questions : 250, dernière mise à jour : 29 octobre 2015 Ajouter une question
Bienvenue sur la FAQ Perl. Cette FAQ a pour vocation de vous enseigner ou de vous faire revoir les notions élémentaires de ce fantastique langage. Perl est très utilisé dans différents domaines depuis la gestion système, le réseaux, l'administration de bases de données, le web (CGI), la bureautique, la conception d'interfaces graphiques ou des contextes scientifiques telle la bioinformatique. Nous espérons que cette FAQ vous sera d'une grande utilité.
Vous souhaitez participer à l'amélioration de cette FAQ, n'hésitez pas !! Commentez
Bonne lecture !
- Qu'est-ce qu'une référence, à quoi ça sert ?
- Comment créer une référence ?
- Qu'est-ce qu'une référence anonyme ?
- Comment utiliser les références, le déférencement !
- Comment parcourir un hachage contenant des références ?
- Cas particulier (tableau à deux dimensions) !
- Astuces sur les références et erreurs à éviter !
- Qu'est-ce qu'une fermeture ?
- Comment générer automatiquement une fonction ?
Les références Perl sont des variables qui permettent de référencer d'autres variables, tableaux, hashs, fonctions ou handles. La notion de référence peut être vue comme les pointeurs en C. Mais pas de panique :-(, c'est beaucoup plus simple que ce que vous croyez ! Vous allez me dire, oui, c'est bien beau, mais à quoi ça sert ? Voici donc un exemple...
Code perl : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | my @tab1 = (1, 2, 3); my @tab2 = ('a', 'b', 'c'); affiche(@tab1, @tab2); sub affiche { my ( @recup1, @recup2 ) = @_; print "Voici votre tableau tab1 récupéré dans ma fonction : @recup1\n"; print "Voici votre tableau tab2 récupéré dans ma fonction : @recup2\n"; return; } |
Code : | Sélectionner tout |
1 2 | Voici votre tableau tab1 récupére dans ma fonction : 1 2 3 a b c Voici votre tableau tab2 récupére dans ma fonction : |
Il en aurait été de même avec des hashs.
Petite explication :
@_ récupère une liste des données (@tab1 et @tab2 concaténés). De ce fait, toutes les données récupérées se retrouvent dans @recup1, @recup2 reste vide. Comment doit-on faire pour que @recup1 et @recup2 soient corrects ? Facile ! Vous avez trouvé ? Les références !!! On passera en argument à la fonction les références de nos tableaux.
Nous avons bien compris avec l'exemple ci-dessus l'utilité des références. La question est maintenant de savoir comment faire pour désigner (créer une référence) un tableau, un hash, une fonction…
Rien de plus simple, il suffit juste de placer un backslash ("\") devant la variable à référencer. Ainsi, la référence $ref_tab de notre tableau @tab s'écrit
Code perl : | Sélectionner tout |
$ref_tab = \@tab;
Code perl : | Sélectionner tout |
1 2 3 4 | my $ref_tableau = \@mon_tableau; my $ref_hash = \%mon_hash; my $ref_fonction = \&ma_fonction; my $ref_handle = \*FILE; |
Code perl : | Sélectionner tout |
1 2 3 | my @mon_tableau = ( 1, 2, 3 ); my $ref_tab = \@mon_tableau; print $ref_tab; |
C'est l'adresse, la référence du tableau @mon_tableau. D'ailleurs, aussi doué que vous soyez, vous avez déjà dû rencontrer des erreurs avec ce genre de caractère !! Généralement, sans le savoir, c'est dû au fait qu'on pense travailler sur un tableau ou une valeur de ce dernier alors que l'on travaille sur sa référence. Sinon, il existe une autre façon de créer des références, qu'on appelle références anonymes, voir ci-dessous.
Excusez mon vocabulaire, mais c'est une façon un peu tordue de créer une référence ! En fait, on crée une référence sur une variable n'existant pas au préalable, ne possédant pas de nom. Je sais, ce n'est pas clair... Ce sont des références sur des structures anonymes en vue d'obtenir des structures de données plus complexes. Un petit exemple vous éclaira, du moins je l'espère !
Code perl : | Sélectionner tout |
1 2 3 4 5 6 7 | my $ref_tab = [ 1, 2, 3 ]; my $ref_hash = { "cle1" => "valeur1", "cle2" => "valeur2", }; print $ref_tab; print $ref_hash; |
Vous remarquez les couleurs rouges pour que vous puissiez prêter attention à la façon d'écrire les références anonymes.
Petit résumé : un tableau s'écrit (1,2,3), une référence anonyme à un tableau [1,2,3].
Bon, c'est bien tout ce blabla, mais comment les utiliser ? On y arrive, on y arrive, allez voir ci-dessous (déférencement).
Ah enfin !!! Après toutes ces explications, vous allez enfin savoir utiliser ces fameuses références !! Tout d'abord, sachez qu'il existe deux façons de les utiliser (eh oui, c'est Perl, avec sa grande capacité à pouvoir écrire du code de différentes façons) :
1) Première façon
- @{$ref_tableau} est identique à @tableau.
- ${$ref_tableau}[0] est identique à $tableau[0]
- %{$ref_hash} est identique à %hash
- ${$ref_hash}{"cle1"} est identique à $hash{"cle1"}
Voici encore plus simple si vous voulez, mais plus bizarre quand on tombe dessus pour la première fois.
Vous pouvez omettre les accolades si $ref a été déclaré : my $ref = \@tableau;
- @{$ref_tableau} est identique à @$ref_tableau.
- ${$ref_tableau}[0] est identique à $$ref_tableau[0]
- %{$ref_hash} est identique à %$ref_hash
- ${$ref_hash}{"cle1"} est identique à $$ref_hash{"cle1"}
Résumé:
@{$ref_tableau} est identique à @$ref_tableau, lui-même identique à @tableau ! En d'autres termes, un tableau est identique au tableau de sa référence ! C'est clair, non ?
Exemple :
- $ref=\@tab => création d'une référence, c'est le référencement
- @{$ref} => c'est le déférencement.
Code perl : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | # Déclaration de mon tableau my @mon_tableau = ( 1, 2, 3 ); # Déclaration de la référence de mon tableau my $ref_tab = \@mon_tableau; print @{$ref_tab}; #ou print @$ref_tab; # et vous obtiendrez : 123 |
2) Deuxième façon
C'est une écriture simplifiée (ressemblant à l'écriture objet pour les connaisseurs). Cette méthode s'utilise surtout lorsque l'on travaille sur un élément de tableau et de hash.
Exemple :
Code perl : | Sélectionner tout |
1 2 3 4 5 | my @tableau = ( 1, 2, 3 ); my $ref_tableau = \@tableau; my %hash = ( "cle1" => "valeur1", "cle2" => "valeur2" ); my $ref_hash = \%hash; |
- $ref_tableau->[0] est identique à ${$ref_tableau}[0] identique à $tableau[0] égal à la valeur 1
- $ref_hash->{"cle1"} est identique à ${$ref_hash}{"cle1"} identique à $hash{"cle1"} égal à la valeur valeur1
Voilà, est-ce compliqué ??
Va falloir relire la doc plusieurs fois au début !! C'est normal !!
Bon pour la route, reprenons notre tout premier exemple (dans la section Qu'est-ce qu'une référence, à quoi ça sert ?) :
Code perl : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | my @tab1 = ( 1, 2, 3 ); my @tab2 = ( 'a', 'b', 'c' ); # On donne en argument à la fonction affiche les références à nos tableaux. affiche( \@tab1, \@tab2 ); sub affiche { # On récupère les références my ( $ref1, $ref2 ) = @_; # Affichage print "Voici votre tableau tab1 récupéré dans ma fonction : @{$ref1}\n"; print "Voici votre tableau tab2 récupéré dans ma fonction : @{$ref2}\n"; } |
Code : | Sélectionner tout |
1 2 3 4 5 | résultat : Voici votre tableau tab1 récupéré dans ma fonction : 1 2 3 Voici votre tableau tab2 récupéré dans ma fonction : a b c Magique, non !! |
Exemple :
Code perl : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | my @tab1 = ( 1, 2, 3 ); my @tab2 = ( 'a', 'b', 'c' ); # On donne en argument à la fonction affiche les références à nos tableaux. affiche( \@tab1, \@tab2 ); print "Voici votre tableau tab1 récupéré dans ma fonction : @tab1\n"; print "Voici votre tableau tab2 récupéré dans ma fonction : @tab2\n"; sub affiche { # On récupère les références my ( $ref1, $ref2 ) = @_; push @{$ref1}, "dudu"; push @{$ref2}, "dudu"; } |
Code : | Sélectionner tout |
1 2 3 4 | résultat : Voici votre tableau tab1 récupéré dans ma fonction : 1 2 3 dudu Voici votre tableau tab2 récupéré dans ma fonction : a b c dudu |
Code perl : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ............ ............ print "Voici votre tableau tab1 récupéré dans ma fonction : @tab1\n"; print "Voici votre tableau tab2 récupéré dans ma fonction : @tab2\n"; sub affiche { # On récupère les références my ( $ref1, $ref2 ) = @_; # Copie de mes tableaux pour que la modification ne soit appliquée que dans la procédure. my @tableau1_interne = @{$ref1}; my @tableau2_interne = @{$ref2}; push @tableau1_interne, "dudu"; push @tableau2_interne, "dudu"; } |
Code : | Sélectionner tout |
1 2 3 4 | résultat : Voici votre tableau tab1 récupéré dans ma fonction : 1 2 3 Voici votre tableau tab2 récupéré dans ma fonction : a b c |
Prenons un exemple de hachage contenant des références, nous allons le parcourir.
Code perl : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #!/usr/bin/perl use strict; use Carp; use warnings; my %HashReferenceComplex = ( 'niv1' => 'valeur 1', 'niv2' => [ 'case0', 'case1', 'case2', 'case3' ], 'niv3' => { 'niv3-1_a' => 'valeur3-1', 'niv3-1_b' => [ 'case0-1', 'case1-1', 'case2-1', 'case3-1' ], 'niv3-1_c' => { 'niv3-2_a' => 'test', }, }, 'niv4' => \&FonctionBonjour, ); sub FonctionBonjour { my $prenom = shift; print "Bonjour $prenom\n"; } |
Code perl : | Sélectionner tout |
1 2 | # Afficher bonjour via le hachage $HashReferenceComplex{'niv4'}->('djibril'); |
Code perl : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | # Afficher bonjour via le hachage $HashReferenceComplex{'niv4'}->('djibril'); # Afficher valeur3-1 print $HashReferenceComplex{'niv3'}{'niv3-1_a'}, "\n"; # Afficher case0-1 print $HashReferenceComplex{'niv3'}{'niv3-1_b'}->[0], "\n"; # Afficher case0 à case3 foreach my $niveau ( @{ $HashReferenceComplex{'niv2'} } ) { print "\t- $niveau\n"; } |
Voici un exemple de tableau à deux dimensions (tableaux de tableaux).
Code perl : | Sélectionner tout |
my @tab2tab = ([1,2], ["a","b"],["toto","tete"],["djibril","Stoyak","vous"]);
- 1re case du tableau @tab2tab => [1,2] ;
- 2e case du tableau @tab2tab => ["a","b"] ;
- 3e case du tableau @tab2tab => ["toto","tete"] ;
- 4e case du tableau @tab2tab => ["djibril","Stoyak","vous"] ;
- Petit rappel : un tableau normal s'écrit avec des parenthèses d'où @tab2tab = (...,...).
un tableau anonyme avec des crochets : [1,2]
@tab2tab contient quatre références anonymes, ainsi pour récupérer la première référence anonyme :
Code perl : | Sélectionner tout |
1 2 3 | my $ref1 = $tab2tab[0]; # c'est-à-dire $ref1 = [1,2]; my $ref4 = $tab2tab[3]; # c'est-à-dire $ref4 = ["djibril","Stoyak","vous"]; # =>Rappel : la première case d'un tableau a pour indice 0. |
Code perl : | Sélectionner tout |
1 2 | my @tab2tab = ([1,2], ["a","b"],["toto","tete"],["djibril","Stoyak","vous"]); my $ref4 = $tab2tab[3]; |
Code perl : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | print ${$ref4}[1]; #=> "Stoyak" print $$ref4[1]; #=> "Stoyak" print ${$tab2tab[3]}[1];#=> "Stoyak" print $$tab2tab[3][1]; #=> ne fonctionnera pas (explication ci-dessous) # Cas particulier des tableaux à plusieurs dimensions, on peut écrire simplement ainsi print $tab2tab[3][1]; #=> "Stoyak" print $tab2tab[3]->[1]; #ou print $ref4->[1]; => "Stoyak" |
Je vous avais expliqué plus haut qu'il était possible d'omettre les accolades et vous avez dû vous demander, pourquoi ${$tab2tab[3]}[1]; est correct et pas $$tab2tab[3][1]; ?
En fait, pour Perl, pour des raisons de priorité entre opérateurs, $tab2tab[3] sera considéré comme une référence, qui n'existe pas. Vous aurez un message d'erreur à l'exécution du script. Si vous utilisez use strict, vous aurez :
Code : | Sélectionner tout |
Global symbol "$tab2tab" requires explicit package name at .............
Code perl : | Sélectionner tout |
print ${$tab2tab[3]}[1]; #=> "Stoyak"
Code perl : | Sélectionner tout |
1 2 | my $ref4 = $tab2tab[3]; #on déclare bien la référence $ref4 print $$ref4[1]; #=> "Stoyak" et c'est Ok. |
Remarque : En général, dès que l'on parle de tableaux à deux dimensions ou plus, il faudra manipuler les références anonymes.
Code perl : | Sélectionner tout |
1 2 | my @tab2tab = ([1,2], ["a","b"],["toto","tete"],["djibril","Stoyak","vous"]); print $tab2dimension[3][1];#=> Stoyak |
Code perl : | Sélectionner tout |
@tab2dimension => $tab2dimension[LIGNE][COLONNE]
Code : | Sélectionner tout |
1 2 3 4 5 6 | ([1,2], ["a","b"],["toto","tete"],["djibril","Stoyak","vous"]) correspond à ligne0 --> 1 2 ligne1 --> a b ligne2 --> toto tete ligne3 --> djibril Stoyak vous |
$tab2dimension[3][1] correspond à la ligne 3 et colonne 1, donc c'est Stoyak
première ligne => ligne0 et première colonne => colonne 0 (on est dans les tableaux !!!!!!)
Voilà, vous maîtrisez maintenant les références !!! Je vais vous faire un petit résumé ci-dessous avec les pièges à éviter.
Si vous souhaitez savoir si $ref est une référence à un tableau ou un hash, voici une fonction Perl
Code perl : | Sélectionner tout |
1 2 3 4 | my $ref_tableau = \@tableau; my $ref_hash = \%hash; print ref $ref_tableau; # ARRAY print ref $ref_hash; # HASH |
- $ref{'toto'} correspond à la valeur de la toto d'un hash nommé ref ;
- $ref->{'toto'} correspond à la valeur d'une référence nommée ref d'un hash.
Prenez pour habitude de donner des noms simples et clairs à vos variables, et de bien commenter vos scripts !
- Ne pas confondre un tableau (1,2,3) et une référence anonyme à un tableau anonyme [1,2,3] ;
- Ne pas confondre un hash ("cle" => "valeur") et une référence anonyme à un hash anonyme {"cle" => "valeur"}.
Attention :
Code perl : | Sélectionner tout |
1 2 3 | ma_fonction(@tab1, @tab2); ou ma_fonction(%hash1, %hash2); |
Code perl : | Sélectionner tout |
1 2 3 | ma_fonction(\@tab1, \@tab2); ou ma_fonction(\%hash1, \%hash2); |
Une fermeture est une référence anonyme vers une fonction. Ces références ont des propriétés très intéressantes, comme celle de garder en mémoire des valeurs de variables lexicales devenues hors de portée. Ainsi, en plus de définir les valeurs d'une fonction lors de l'appel, on peut aussi le faire lors de la définition. Un petit exemple :
Code perl : | Sélectionner tout |
1 2 3 4 5 6 | my $ref; { my $var = "Salut"; $ref = sub {return "$var @_";}; } print $ref->("Larry"); # affiche Salut Larry, alors que $var n'existe plus ! |
On pourrait aussi passer $var à ferm et retourner $ref à la fin : à chaque appel de ferm on obtiendrait une fermeture (donc une référence vers un sous-programme) qui garderait la valeur de $var utilisée à l'appel de ferm. Cela donnerait ceci :
Code perl : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | sub ferm { my ($var) = @_; my $ref = sub { return "$var @_"; }; return $ref; } my $ref = ferm("Salut"); #plus tard print $ref->("Larry"); #affiche Salut Larry |
En bouclant autour d'une fermeture, on peut créer des fonctions ayant un code semblable mais des noms différents. Le problème est qu'une fermeture n'a pas de nom, mais on peut le contourner : il est en effet possible de lier une référence de code à un nom déjà existant en passant par les typeglobs.
Par exemple, on veut deux fonctions fic1 et fic2 qui écrivent leurs paramètres dans des fichiers qui ont respectivement pour handle FIC1 et FIC2. Les deux fonctions sont très proches, elles ne diffèrent que par le fichier dans lequel écrire. Voilà comment générer ces deux fonctions en bouclant autour d'une fermeture :
Code perl : | Sélectionner tout |
1 2 3 4 5 6 7 | foreach my $champ (qw(fic1 fic2)) { my $handle = uc $champ; # met $champ en majuscule no strict 'refs'; #Autorise les références symboliques *$champ = sub {print $handle "@_";}; # affecte la fermeture en question au typeglob } fic1("Salut !"); #écrit salut dans FIC1 |
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.