[Toulouse-pm] relecture perlreftut

Ronan Le Hy rlehy at free.fr
Fri Dec 13 07:57:00 CST 2002


[-> all qw/lyon.pm toulouse.pm/]

Salut,

Est-ce qu'un mongueur ou un mongueur-cong aurait une seconde pour relire 
la traduction que je viens de faire de perlreftut (le tutoriel de mjd 
sur les références)?


Ronan
-------------- next part --------------

=head1 NOM

perlreftut - le très court tutoriel de Mark sur les références

=head1 DESCRIPTION

Une des caractéristiques nouvelles les plus importantes de Perl 5 a
été la capacité de gérer des structures de données compliquées comme
les tableaux multidimensionels et les tables de hachage
imbriquées. Pour les rendre possibles, Perl 5 a introduit un mécanisme
appelé "références" ; l'utilisation de celles-ci est le moyen de
travailler avec des donnée complexes structurées en
Perl. Malheureusement, cela fait une grande quantité de syntaxe nouvelle à
apprendre, et la page de manuel est parfois difficile à suivre. Cette
dernière est très complète, et cela peut être un problème parce qu'il
est difficile d'en tirer ce qui est important et ce qui ne l'est pas.

Heureusement, vous avez seulement besoin de savoir 10% de ce qui est
dans la page de manuel principale pour tirer 90% de son bénéfice. Cette
page espère vous montrer ces 10%.

=head1 Qui a Besoin de Structures de Données Compliquées?

Un problème qui revenait souvent avec Perl 4 était celui de la
représentation d'une table de hachage dont les valeurs sont des
listes. Perl 4 avait les tables de hachage, bien sûr, mais les valeurs
devaient être des scalairee ;  elles ne pouvaient être des listes.

Pourquoi voudrait-on utiliser une table de hachage contenant des
listes ? Prenons un exemple simple. Vous avez un fichier contenant des
noms de villes et de pays, comme ceci:

	Chicago, USA
	Frankfort, Allemagne
	Berlin, Allemagne
	Washington, USA
	Helsinki, Finlande
	New York, USA

et vous voulez produire une sortie comme cela, avec chaque pays
mentionné une seule fois, suivi d'une liste des villes de ce pays :

	Finlande: Helsinki.
	Allemagne: Berlin, Frankfort.
	USA:  Chicago, New York, Washington.

La façon naturelle de faire ceci est de construire une table de
hachage dont les clés sont les noms des pays. A chaque pays clé on
associe une liste des villes de ce pays. Chaque fois qu'on lit une ligne
en entrée, on la sépare en un pays et une ville, on recherche la liste
de villes déjà connues pour ce pays, et on y ajoute la nouvelle
ville. Quand on a fini de lire les données en entrée, on parcourt la
table de hachage, en triant chaque liste de villes avant de
l'afficher.

Si les valeurs des tables de hachage ne peuvent être des listes, c'est
perdu. En Perl 4, c'est le cas ; ces valeurs ne peuvent être que de
chaînes de caractères. C'est donc perdu. Nous devrions probablement
essayer de combiner toutes les villes dans une seule grande chaîne de
caractères, et au moment d'écrire la sortie, couper cette
chaîne pour en faire une liste, la trier, et la re-convertir en
chaîne de caractères. C'est compliqué, et il est facile de faire des
erreurs dans le processus. C'est surtout frustrant, parce que Perl a
déjà de très belles listes qui résoudraient le problème, si seulement
nous pouvions les utiliser.

=head1 La Solution

Avant même que Perl 5 ne pointât le bout de son nez, nous étions donc
coincés avec ce fait de conception : les valeurs de tables de hachage
doivent être des scalaires. Les références sont la solution à ce
problème.

Une référence est une valeur scalaire qui I<fait référence à> un
tableau entier ou à une table de hachage entière (ou à à peu près
n'importe quoi d'autre). Les noms sont une forme de référence dont
vous êtes déjà familier. Pensez au Président des Etats-Unis d'Amerique:
ce n'est qu'un tas désordonné et malpratique de sang et d'os. Mais
pour parler de lui, ou le représenter dans un programme d'ordinateur,
tout ce dont vous avez besoin est le sympathique et maniable scalaire
"George Bush".

Les références en Perl sont comme des noms pour les tableaux et les
tables de hachage. Ce sont des noms privés et internes de Perl, vous
pouvez donc être sûr qu'ils ne sont pas ambigus. Au contraire de
"George Bush", une référence pointe vers une seule chose, et il est
toujours possible de savoir vers quoi. Si vous avez une référence à un
tableau, vous pouvez accéder au tableau complet qui est derrière. Si
vous avez une référence à une table de hachage, vous pouvez accéder à
la table entière. Mais la référence reste un scalaire, compact et
facile à manipuler.

Vous ne pouvez pas construire une table de hachage dont les valeurs
sont des tableaux : les valeurs des tables de hachage ne peuvent être
que des scalaires. Nous y somme condamnés. Mais une seule référence
peut pointer vers un tableau entier, et les références sont des
scalaires, donc vous pouvez avoir une table de hachage de références à
des tableaux, et elle agira presque comme une table de hachage de
tableaux, et elle pourra servir juste comme une table de hachage de
tableaux.

Nous reviendrons à notre problème de villes et de pays plus tard,
après avoir introduit un peu de syntaxe pour gérer les références.


=head1 Syntaxe

Il n'y a que deux façons de construire une référence, et deux façons de
l'utiliser une fois qu'on l'a.

=head2 Construire des Références

B<Règle de Construction 1>

Si vous mettez un C<\> devant une variable, vous obtenez une référence
à cette variable.

    $tref = \@tableau;       # $tref contient maintenant une référence
                             # à @tableau
    $href = \%hachage;       # $href contient maintenant une référence
                             # à %hachage

Une fois que la référence est stockée dans une variable comme $tref ou
$href, vous pouvez la copier ou la stocker ailleurs comme n'importe
quelle autre valeur scalaire :

    $xy = $tref;             # $xy contient maintenant une référence
                             # à @tableau
    $p[3] = $href;           # $p[3] contient maintenant une référence
                             # à  %hachage
    $z = $p[3];              # $z contient maintenant une référence
                             # à  %hachage

Ces exemples montrent comment créer des références à des variables
avec un nom. Parfois, on veut utiliser un tableau ou une table de
hachage qui n'a pas de nom. C'est un peu comme pour les chaînes de
caractères et les nombres : on veut être capable d'utiliser la chaîne
C<"\n"> ou le nombre 80 sans avoir à les stocker dans une variable
nommée d'abord.

B<Règle de Construction 2>

C<[ ELEMENTS ]> crée un nouveau tableau anonyme, et renvoie une
référence à ce tableau. C<{ ELEMENTS }> crée une nouvelle table de
hachage anonyme et renvoie une référence à cette table.

    $tref = [ 1, "toto", undef, 13 ];
    # $tref contient maintenant une référence à un tableau

    $href = { AVR => 4, AOU => 8 };
    # $href contient maintenant une référence à une table de hachage


Les références obtenues grâce à la règle 2 sont de la même espèce que
celles obtenues par la règle 1 :

	# Ceci :
	$tref = [ 1, 2, 3 ];

	# Fait la même chose que cela :
	@tableau = (1, 2, 3);
	$tref = \@tableau;


La première ligne est une abbréviation des deux lignes suivantes, à
ceci près qu'elle ne crée pas la variable tableau superflue
C<@tableau>.


=head2 Utiliser les Références


Une fois qu'on a une référence, que peut-on en faire? C'est une valeur
scalaire, et nous avons vu que nous pouvons la stocker et la
récupérer ensuite comme n'importe quel autre scalaire. Il y juste deux
façons de plus de l'utiliser :

B<Règle d'Utilisation 1>

Si C<$tref> contient une référence à un tableau, vous pouvez écrire
C<{$tref}> là où vous mettriez le nom d'un tableau. Par exemple,
C<@{$tref}> à la place de C<@array>.

En voici quelques exemples :

Tableaux :

	@t		@{$tref}		Un tableau
	reverse @t	reverse @{$tref}	Retourner le tableau
	$t[3]		${$tref}[3]		Un élément du tableau
	$t[3] = 17;	${$tref}[3] = 17	Affecter un élément


Sur chaque ligne, les deux expresions font la même chose. Celles de
gauche travaillent sur le tableau C<@t>, et celles de droite
travaillent sur le tableau vers lequel pointe C<$tref> ; mais une fois
qu'elle ont accédé au tableau sur lequel elles opèrent, elles leur
font exactement la même chose.


On utilise une référence à une table de hachage C<exactement> de la
même façon :

	%h		%{$href}	      Une table de hachage
	keys %h		keys %{$href}	      Obtenir les clés de la 
                                              table
	$h{'bleu'}	${$href}{'bleu'}      Un élément de la table
	$h{'bleu'} = 17	${$href}{'bleu'} = 17 Affecter un élément


B<Règle d'Utilisation 2>

C<${$tref}[3]> est trop dur à lire, vous pouvez donc écrire C<<
$tref->[3] >> à la place.

C<${$href}{bleu}> est trop dur à lire, vous pouvez donc écrire
C<< $href->{bleu} >> à la place.

La plupart du temps, quand vous avez un tableau ou une table de
hachage, vous voulez modifier ou obtenir un élément
particulier. C<${$tref}[3]> et C<${$tref}{'bleu'}> ont trop de
ponctuation, et Perl vous laisse prendre un raccourci.


Si C<$tref> est une référence à un tableau, alors C<< $tref->[3] >>
est le quatrième élément du tableau. Ne mélangez pas ça avec
C<$tref[3]>, qui est le quatrième élément d'un tout autre tableau,
trompeusement nommé C<@tref>. C<$tref> et C<@tref> ne sont pas reliés,
pas plus que C<$truc> et C<@truc>.


De la même façon, C<< $href->{'bleu'} >> est une partie de la table de
hachage vers laquelle pointe C<$href>, et qui ne porte peut-être pas
de nom. C<$href{'bleu'}> est une partie de la table de hachage
trompeusement nommée C<%href>. Il est facile d'oublier le C<< -> >>,
et si cela vous arrive vous obtiendrez des résultats étranges comme
votre programme utilisera des tableaux et des tables de hachage issus
de tableaux et de tables de hachages qui n'étaient pas ceux que vous
aviez l'intention d'utiliser.


=head1 Un Exemple

Voyons un rapide exemple de l'utilité de tout ceci.

D'abord, souvenez-vous que C<[1, 2, 3]> construit un tableau anonyme
contenant C<(1, 2, 3)>, et vous renvoie une référence à ce tableau.

Maintenant, considérez

	@t = ( [1, 2, 3],
               [4, 5, 6],
	       [7, 8, 9]
             );

@t est un tableau à trois éléments, et chacun d'entre eux est une
référence à un autre tableau.

C<$t[1]> est l'une de ces références. Elle pointe vers un tableau,
celui contenant C<(4, 5, 6)>, et puisque c'est une référence à un
tableau, la C<REGLE D'UTILISATION 2>dit que nous pouvons écrire C<<
$t[1]->[2] >> pour accéder au troisième élément du tableau. C<<
$t[1]->[2] >> est le 6. De la même façon, C<< $t[0]->[1] >> est le
2. Nous avons ce qui ressemble à un tableau à deux dimensions ; vous
pouvez écrire C<< $t[LIGNE]->[COLONNE] >> pour obtenir ou modifier
l'élément se trouvant à une ligne et une colonne données du tableau.


Notre notation est toujours quelque peu maladroite, voici donc un
raccourci de plus :

=head1 Règle de la Flèche

Entre deux B<indices>, la flèche et facultative.

A la place de C<< $t[1]->[2] >>, nous pouvons écrire C<$t[1][2]> ;
cela veut dire la même chose. A la place de C<< $t[0]->[1] >>, nous
pouvons écrire C<$t[0][1]> ; cela veut dire la même chose.

Maintenant on dirait vraiment un tableau à deux dimensions !

Vous pouvez voir pourquoi les flèches sont importantes. Sans elles,
nous devrions écrire C<${$t[1]}[2]> à la place de C<$t[1][2]>. Pour
les tableaux à trois dimensions, elles nous permettent d'écrire
C<$x[2][3][5]> à la place de l'illisible C<${${$x[2]}[3]}[5]>.


=head1 Solution

Voici maintenant la réponse au problème que j'ai posé plus haut, qui
consistait à reformatter un fichier de villes et de pays.

    1   while (<>) {
    2     chomp;
    3     my ($ville, $pays) = split /, /;
    4     push @{$table{$pays}}, $ville;
    5   }
    6
    7   foreach $pays (sort keys %table) {
    8     print "$pays: ";
    9     my @villes = @{$table{$pays}};
   10     print join ', ', sort @villes;
   11     print ".\n";
   12	}


Le programme a deux parties : les lignes 1 à 5 lisent les données et
construisent une structure de données, et les lignes 7 à 12 analysent
les données et impriment un rapport.


Dans la première partie, la ligne 4 est la plus importante. Nous
allons construire une table de hachage, C<%table>, dont les clés sont
les noms de pays, et dont les valeurs sont des (références à des)
tableaux de noms de villes. Après avoir lu une ville et un pays, le
programme accède à C<$table{$pays}>, qui contient (une référence à)
une liste des villes vues dans ce pays jusque là. La ligne 4 est tout
à fait analogue à

	push @tableau, $ville;

sauf que le nom C<tableau> a été remplacé par la référence
C<{$table{$pays}}>. Le C<push> ajoute une ville à la fin du tableau
auquel il est fait référence.


Dans la seconde partie, la ligne 9 est celle qui compte. Encore une
fois, C<$table{$pays}> est (une référence à) la liste de villes dans
le pays, donc nous pouvons retrouver la liste originale et la copier
dans le tableau C<@villes>, en utilisant C<@{$table{$pays}}>. La ligne
9 est tout à fait analogue à

	@villes = @tableau;

sauf que le nom C<tableau> a été remplacé par la référence
C<{$table{$pays}}>. Le C<@> dit à Perl d'obtenir le tableau complet.

Le reste du programme consiste juste en l'usage familier de C<chomp>,
C<split>, C<sort>, C<print>, et n'implique aucune référence.


Il y a un point délicat que j'ai ignoré. Imaginez que le programme
vienne de lire la première ligne de données, qui se trouve mentionner
la Grèce. Le contrôle est à la ligne 4, C<$pays> vaut C<'Grèce'>, et
C<$ville> vaut C<'Athènes'>. Puisque c'est la première ville qu nous
voyons pour la Grèce, C<$table{$pays}> n'est pas défini -- en fait, il
n'y a pas de clé nommée C<'Grèce'> dans C<%table>. Que fait alors la
ligne 4 ?

 4	push @{$table{$pays}}, $ville;


Nous avons affaire à Perl, qui fait juste ce qu'il faut. Perl voit que
vous voulez pousser C<Athènes> sur un tableau qui n'existe pas, et
crée donc aimablement un nouveau tableau vide anonyme pour vous,
l'installe dans la table, et pousse C<Athènes> dedans. On appelle cela
"l'autovification". 


=head1 Le Reste

J'ai promis de vous donner accès à 90% du bénéfice avec 10% des
détails, et cela implique que j'ai laissé de côté 90% des
détails. Maintenant que vous avez une vue d'ensemble des éléments
importants, il devrait vous être plus facile de lire la page de manuel
L<perlref>, qui passe en revue 100% des détails.


Quelques unes de grande lignes de L<perlref> :

=over 4

=item *

Vous pouvez créer des références à n'importe quoi, ce qui inclut des
scalaires, des fonctions, et d'autres références.

=item *

Dans la B<REGLE D'UTILISATION 1>, vous pouvez omettre les accolades
quand ce qui est à l'intérieur est une variable scalaire atomique
comme C<$tref>. Par exemple, C<@$tref> est identique à C<@{$tref}>, et
C<$$tref[1]> est identique à C<${$tref}[1]>. Si vous ne faites que
commencer, vous pourriez préférer adopter l'habitude de toujours
écrire les accolades.


=item *

Pour voir si une variable contient une référence, utilisez la fonction
"ref". Elle renvoie vrai si son argument est une référence. En fait,
c'est encore mieux que ça : elle renvoie HASH pour les références à
une table de hachage et ARRAY pour les références à un tableau.

=item *

Si vous essayez d'utiliser une référence comme une chaîne de
caractères, vous obtenez quelquechose comme

	ARRAY(0x80f5dec)   ou    HASH(0x826afc0)

Si jamais vous voyez une chaîne de caractères qui ressemble à ça, vous
saurez que vous avez imprimé une référence par erreur.


Un effet de bord de cette représentation est que vous pouvez utiliser
C<eq> pour savoir si deux références pointent vers la même
chose. (Mais d'ordinaire vous devriez plutôt utiliser C<==> parce que
c'est beaucoup plus rapide.)

=item *

Vous pouvez utiliser une chaîne de caractères comme si c'était une
référence. Si vous utilisez la chaîne C<"foo"> comme une référence à
un tableau, elle est prise comme une référence au tableau C<@foo>. On
appelle cela une C<référence symbolique>.


=back

Vous pourriez préférer continuer avec L<perllol> au lieu de
L<perlref> ;  il y est traité des listes de listes et des tableaux
multidimensionnels en détail. Après cela, vous devriez avancer vers
L<perldsc> ; c'est un livre de recettes pour les structures de
données (I<Data Structure Cookbook>) qui montre les recettes pour
utiliser et imprimer les tableaux de tables de hachage, les tables de
hachage de tableaux, et les autres sortes de données.

=head1 Résumé

Tout le monde a besoin de structures de données complexes, et les
références sont le moyen d'y accéder en Perl. Il y a quatre règles
importantes pour manipuler les références : deux pour les construire,
et deux pour les utiliser. Une fois que vous connaissez ces règles,
vous pouvez faire la plupart des choses importantes que vous devez
faire avec des références.

=head1 Crédits

Auteur : Mark-Jason Dominus, Plover Systems
(C<mjd-perl-ref+ at plover.com>)

Cet article est paru à l'origine dans I<The Perl Journal>
( http://www.tpj.com/ ) volume 3, # 2.  Réimprimé avec permission.

Le titre original était I<Understand References Today> (I<Comprendre
les Références Aujourd'hui>).


=head2 Distribution Conditions

Copyright 1998 The Perl Journal.

When included as part of the Standard Version of Perl, or as part of
its complete documentation whether printed or otherwise, this work may
be distributed only under the terms of Perl's Artistic License.  Any
distribution of this file or derivatives thereof outside of that
package require that special arrangements be made with copyright
holder.

Irrespective of its distribution, all code examples in these files are
hereby placed into the public domain.  You are permitted and
encouraged to use this code in your own programs for fun or for profit
as you see fit.  A simple comment in the code giving credit would be
courteous but is not required.

=head2 Conditions de Distribution

Copyright 1998 The Perl Journal.

Quand il est partie de la Version Standard de Perl, ou de sa
documentation complète imprimée ou non, ce travail peut être distribué
uniquement selon les termes de la License Artistique de
Perl. N'importe quelle distribution de ce fichier ou de ses dérivés
hors de cet ensemble requiert un arrangement spécial avec le détenteur
du copyright.

Quel que soit leur mode de distribution, tous les exemples de code de
ces fichiers sont par ce document placés dans le domaine public. Vous
êtes autorisé et encouragé à utiliser ce code dans vos programmes à
fins commerciales ou d'amusement, comme vous le souhaitez. Un simple
commentaire dans le code signalant son origine serait courtois mais
n'est pas requis.


=head1 VERSION FRANÇAISE

Cette traduction française correspond à la version anglaise distribuée
avec perl 5.8.0.  Pour en savoir plus concernant ces traductions,
consultez http://www.enstimac.fr/Perl/ .

=head1 TRADUCTION

Traduction initiale : Ronan Le Hy (C<rlehy at free.fr>).

=head1 RELECTURE

Personne pour l'instant.

=cut


More information about the Toulouse-pm mailing list