====== Références ======
====== 1. Introduction ======
Par conception, les listes et les hashes de Perl ne peuvent contenir que des éléments de type scalaire. C'est dommage, cela peut être à priori très utilie d'avoir des listes de listes, des hashes de listes, etc.
La solution consiste à pouvoir désigner n'importe quel type de donnée Perl (scalaire, liste, hash) à l'aide d'un scalaire spécial, la **référence**. Il s'agit d'un mécanisme analogue aux pointeurs en C ou C++.
L'utilisation des références demande des syntaxes particulières et différentes de ce que nous avons vu jusqu'ici, mais la manipulation des types de base reste bien entendu inchangée.
====== 2. Créer des références ======
===== Obtenir la référence d'une variable =====
Si vous avez déjà des variables et que vous voulez obtenir leur référence, il suffit d'utiliser l'opérateur //backslash// :
my $ref_scalaire = \$scalaire;
my $ref_liste = \@liste;
my $ref_hash = \%hash;
===== Définir directement des références =====
Il peut être utile d'obtenir des références sans créer au préalable une variable, par exemple pour initialiser des structures de données que l'on utilisera que via leur référence :
my $ref_scalaire = \42;
my $ref_liste = ["pierre", "papier", "ciseau"];
my $ref_hash = { "nom" => "Perl", "date" => "1987" };
Notez l'utilisation des crochets et des accolades en lieu et place des parenthèses.
====== 3. Utilisation des références ======
La référence en tant que telle ne représente pas la structure qu'elle désigne, par exemple si on l'affiche :
my $ref = \42;
print "$ref\n"; # Affiche SCALAR(0x814f5e8)
===== Déréférencement =====
Pour manipuler la structure de donnée référencée, on préfixe par le symbole du type référencé et on met la référence entre accolades :
my $ref = \42;
print "${$ref}\n"; # Affiche 42
my $ref_liste = ["pierre", "papier", "ciseau"];
print join(" - ", @{$ref_liste});
print ${$ref_liste}[0];
my $ref_hash = { "nom" => "Perl", "date" => "1987" };
print join(" - ", keys %{$ref_hash});
print %{$ref_hash}{"nom"};
Souvent, on veut juste extraire un élément d'une liste ou d'un hash, et cette syntaxe est trop lourde et peu lisible. Dans ce cas, il existe un raccourci :
my $ref_liste = ["pierre", "papier", "ciseau"];
print $ref_liste->[0];
my $ref_hash = { "nom" => "Perl", "date" => "1987" };
print $ref_hash->{"nom"};
Il existe enfin un dernier raccourci: il est possible de ne pas spécifier la flèche entre deux indiçages de liste (ceci permettant d'implémenter les tableaux multidimensionnels sans s'arracher les cheveux) :
my @matrice = (
[1, 0, 2],
[0, 1, 0],
[3, 0, 1]
);
print ${$matrice[$_]}[$_] foreach (1..3);
print $matrice[$_]->[$_] foreach (1..3);
print $matrice[$_][$_] foreach (1..3);
===== Copie =====
Si on copie des références, on ne copie pas les structures de données qu'elles désignent. On obtient simplement deux noms pour accéder aux mêmes données :
my $number = 42;
my $ref1 = \$number;
${$ref1} = 33; # $number vaut 33
my $ref2 = $ref1;
${$ref2} = 57; # $number vaut 57
===== Exemples =====
Avec un hash de listes :
my %notes = (
"Pierre" => [15, 12, 10.5],
"Jean" => [9, 18, 11]
);
print "La dernière note de Pierre est ${$notes{"Pierre"}}[0]";
print "La dernière note de Pierre est $notes{"Pierre"}->[0]";
Ou alors une liste de hashes: quand on parcourt la liste, les éléments sont des références, on utilise donc de préférence la notation
$_->... :
my @eleves = (
{ "nom" => "Pierre", "moyenne" => 12.5, niveau => "2" },
{ "nom" => "Jean", "moyenne" => 10.5, niveau => "1" },
);
foreach (@eleves) {
print "${$_}{'nom'} a une moyenne de ${$_}{'moyenne'}";
print "$_->{'nom'} a une moyenne de $_->{'moyenne'}";
}
Enfin, les références sont particulièrement utiles pour pouvoir passer des listes et des hashes à des fonctions sans que ces dernières soit mises à plat dans la liste //@_// :
sub rapport {
my $temperatures = shift;
my $precipitation = shift;
print "Mois $_: $temperatures->[$_]°C, $precipitation->[$_]\n" foreach
(1..12);
}
**Références à des références :**
my $maison = "maison particulière préfabriquée";
my @voitures = ("Citroën","Peugeot","Renault","Porsche");
my %famille = (femme => "Fanny", fille => "Anne", fils => "Florian");
my %pointeur_hash = (
pointeur_maison => \$maison,
pointeur_voiture => \@voitures,
pointeur_famille => \%famille
);
my $pointeur = \%pointeur_hash;
print "(1.) $pointeur->{pointeur_maison}\n";
print "(2.) ${$pointeur->{pointeur_maison}}\n";
print "(3.) $pointeur->{pointeur_voiture}\n";
print "(4.) @{$pointeur->{pointeur_voiture}}\n";
print "(5.) $pointeur->{pointeur_voiture}->[2]\n";
print "(6.) $pointeur->{pointeur_voiture}[3]\n";
print "(7.) $pointeur->{pointeur_famille}\n";
print "(8.)", %{$pointeur->{pointeur_famille}},"\n";
print "(9.) $pointeur->{pointeur_famille}->{femme}\n";
print "(10.) $pointeur->{pointeur_famille}{fils}\n"
Affichera :
(1.) SCALAR(0x8154558)
(2.) maison particulière préfabriquée
(3.) ARRAY(0x8154588)
(4.) Citrën Peugeot Renault Porsche
(5.) Renault
(6.) Porsche
(7.) HASH(0x8154a44)
(8.) filleAnnefilsFlorianfemmeFanny
(9.) Fanny
(10.) Florian