Rechercher une page de manuel
perlref
Langue: pl
Version: perl 5.005, patch 03 (openSuse - 09/10/07)
Section: 1 (Commandes utilisateur)
Sommaire
NAZWA
perlref - odwo³ania i zagnie¿d¿one struktury danych w PerluUWAGA
To jest pe³na dokumentacja dotycz±ca wszelkich aspektów odwo³añ. Krótszy, wprowadzaj±cy wstêp to najistotniejszych cech znajdziesz w podrêczniku perlreftut(1).OPIS
Przed wersj± 5 Perla przedstawianie z³o¿onych struktur danych by³o trudne, gdy¿ wszystkie odwo³ania musia³y byæ symboliczne - a nawet wtedy ciê¿ko by³o odnosiæ siê do zmiennej zamiast do pozycji w tablicy symboli. Obecnie Perl nie tylko u³atwia pos³ugiwanie siê symbolicznymi odwo³aniami do zmiennych, ale tak¿e pozwala na u¿ycie ``sta³ych'' odwo³añ (hard references) do dowolnego kawa³ka danych lub kodu. Sta³e dowi±zanie mo¿e byæ przechowywane w dowolnym skalarze. Poniewa¿ tablice i tablice asocjacyjne (hasze) zawieraj± skalary, to mo¿esz teraz ³atwo budowaæ tablice tablic, tablice haszy, hasze tablic, tablice haszy funkcji i tak dalej.Odwo³ania sta³e s± sprytne --- utrzymuj± za ciebie liczniki odwo³añ, automatycznie zwalniaj±c rzecz, do której odnosi siê odwo³anie, je¶li jej licznik odwo³añ zejdzie do zera. (Uwaga: liczniki odwo³añ dla warto¶ci w strukturach danych odnosz±cych siê do samych na siebie (self-referential) lub strukturach cyklicznych mog± nie schodziæ do zera bez pewnej drobnej pomocy; patrz sekcja Two-Phased Garbage Collection w podrêczniku perlobj(1), zawieraj±ca bardziej szczegó³owy opis.) Je¶li taka rzecz jest obiektem, to obiekt jest niszczony. Wiêcej o obiektach znajdziesz w podrêczniku perlobj(1). (W pewnym sensie, wszystko w Perlu jest obiektem, ale zwykle rezerwujemy to s³owo dla odwo³añ do obiektów, które zosta³y oficjalnie "pob³ogos³awione" (``blessed'') [tj.zakwalifikowane jako obiekty] w pakiecie klasy.)
Odwo³ania symboliczne s± nazwami zmiennych lub innych obiektów; zupe³nie tak jak dowi±zania symboliczne (symbolic links) w uniksowym systemie plików zawieraj± wy³±cznie nazwê pliku. Notacja *glob jest rodzajem odwo³ania symbolicznego. (Odwo³ania symboliczne nazywane s± czasami ``soft references'' [odwo³aniami miêkkimi, w przeciwieñstwie do "hard r."-"twardych"], ale proszê nie nazywaj ich tak; odwo³ania s± wystarczaj±co zbijaj±ce z panta³yku bez zbêdnych synonimów.)
W przeciwieñstwie do nich, odwo³ania sta³e przypominaj± dowi±zania sta³e (hard links) uniksowego systemu plików: s³u¿± do udostêpniania obiektu bez zwracania uwagi na to, jaka jest jego (inna) nazwa. Tam, gdzie u¿yto s³owa ``odwo³anie'' bez przymiotnika, jak w poni¿szym akapicie, mówi siê zwykle o odwo³aniu sta³ym.
W Perlu odwo³ania s± ³atwe w u¿yciu. Jest tylko jedna nadrzêdna zasada: Perl nie wykonuje niejawnego odwo³ywania b±d¼ dereferowania odwo³añ. [Dereferencing: odniesienie siê z powrotem do obiektu, rzeczy na któr± wskazuje odwo³anie]. Gdy skalar przechowuje odwo³anie, to zawsze zachowuje siê jak zwyk³y skalar. Nie zaczyna magicznie byæ tablic±, haszem czy procedur±; musisz wprost nakazaæ takie zachowanie, wykonuj±c dereferencjê.
Tworzenie odwo³añ
Odwo³ania mog± byæ tworzone na kilka sposobów.- 1.
- Przez zastosowanie operatora odwróconego uko¶nika do zmiennej, procedury lub warto¶ci. (Dzia³a to bardzo podobnie do operatora & (zwracaj±cego adres) w jêzyku C.) Zauwa¿, ¿e konstrukcja ta tworzy KOLEJNE odwo³anie do zmiennej, gdy¿ w tablicy symboli istnieje ju¿ odwo³anie do tej zmiennej. Jednak odwo³anie z tablicy symboli mo¿e znikn±æ, a nadal bêdziesz mieæ odwo³anie, które zwróci³ odwrócony uko¶nik. Oto kilka przyk³adów:
$scalarref = \$foo; $arrayref = \@ARGV; $hashref = \%ENV; $coderef = \&handler; $globref = \*foo;
Przy u¿yciu operatora odwróconego uko¶nika nie jest mo¿liwe utworzenie prawdziwego odwo³ania do uchwytu IO (uchwytu pliku lub katalogu). Mo¿esz co najwy¿ej uzyskaæ odwo³anie do typeglob bêd±cego faktycznie pe³nym wpisem w tablicy symboli. (Przeczytaj jednak poni¿ej obja¶nienie sk³adni *foo{CO¦}.) Mimo to, mo¿esz nadal u¿ywaæ typeglob i odwo³añ do nich jakby by³y one uchwytami IO. - 2.
- Odwo³anie do anonimowej tablicy mo¿na stworzyæ pos³uguj±c siê nawiasami kwadratowymi:
$arrayref = [1, 2, ['a', 'b', 'c']];
Utworzyli¶my odwo³anie do anonimowej tablicy trzech elementów, której ostatni element jest z kolei odwo³aniem do innej anonimowej tablicy trzech elementów. (Dostêp do niej umo¿liwi opisana dalej sk³adnia tablic wielowymiarowych. Na przyk³ad, dla powy¿szego przyk³adu $arrayref->[2][1] zwraca warto¶æ ``b''.)Zauwa¿, ¿e stworzenie odwo³ania do listy wyliczanej nie jest tym samym, co u¿ycie nawiasów kwadratowych. Jest to natomiast tym samym, co stworzenie listy odwo³añ!
@list = (\$a, \@b, \%c); @list = \($a, @b, %c); # to samo!
W przypadku szczególnym, \(@foo) zwraca listê odwo³añ do zawarto¶ci @foo, nie za¶ odwo³anie do samej @foo. Podobnie jest dla %foo, z wyj±tkiem tego, ¿e odwo³ania-klucze odnosz± siê do kopii (gdy¿ klucze s± ³añcuchami znakowymi, a nie dowolnymi skalarami). - 3.
- Odwo³anie do anonimowej tablicy asocjacyjnej (hasza) mo¿na utworzyæ u¿ywaj±c nawiasów klamrowych:
$hashref = { 'Adam' => 'Ewa', 'Clyde' => 'Bonnie', };
Powy¿sze konstruktory anonimowych haszy i tablic mo¿na swobodnie ³±czyæ. Umo¿liwia to otrzymywanie dowolnie skomplikowanych struktur. Opisana sk³adnia wielowymiarowych tablic/haszy dzia³a tak¿e dla nich. Warto¶ci w powy¿szym przyk³adzie by³y litera³ami, ale równie dobrze mog³yby byæ zmiennymi czy wyra¿eniami, gdy¿ perlowe operatory przypisania (nawet wewn±trz local() czy my()) s± wykonywalnymi instrukcjami, a nie jedynie deklaracjami dla fazy kompilacji.Poniewa¿ nawiasy klamrowe s³u¿± do kilku innych rzeczy, a tak¿e do tworzenia BLOKów, mo¿esz byæ czasem zmuszony do unikniêcia dwuznaczno¶ci tych nawiasów na pocz±tku instrukcji. Wystarczy wówczas umieszczenie przed nimi + lub return, by Perl zorientowa³ siê, ¿e otwieraj±cy nawias klamrowy nie rozpoczyna BLOKu. Oszczêdno¶æ i zalety mnemoniczne u¿ycia nawiasów klamrowych warte s± takiego sporadycznego zamieszania.
Na przyk³ad, je¶li chcia³by¶, by funkcja tworzy³a nowy hasz i zwraca³a odwo³anie do niego, to masz takie mo¿liwo¶ci:
sub hashem { { @_ } } # ¼le, ale bez komunikatu o b³êdzie sub hashem { +{ @_ } } # ok sub hashem { return { @_ } } # ok
Z drugiej strony, je¶li chcesz drugiego znaczenia nawiasów (blok), zrób tak:sub showem { { @_ } } # dwuznaczne (obecnie ok, ale mo¿e siê zmieniæ) sub showem { {; @_ } } # ok sub showem { { return @_ } } # ok
Zwróæ uwagê, ¿e pocz±tkowe +{ i {; zawsze s³u¿± do wykluczenia dwuznaczno¶ci wyra¿enia, aby znaczy³o albo odwo³anie do HASZa albo BLOK. - 4.
- Mo¿na utworzyæ odwo³anie do anonimowej procedury u¿ywaj±c sub bez nazwy procedury:
$coderef = sub { print "Bums!\n" };
Zwróæ uwagê na obecno¶æ ¶rednika. Poza faktem, ¿e wewnêtrzny kod nie jest wykonywany natychmiast, sub {} jest bardziej operatorem ni¿ deklaracj±, podobnie zreszt± jak do{} czy eval{}. (Jednak, niezale¿nie od tego, ile razy wykonasz powy¿sz± liniê (chyba ¿e jeste¶ wewn±trz eval("...")), $coderef wci±¿ bêdzie zawieraæ odwo³anie do TEJ SAMEJ anonimowej procedury.)Procedury anonimowe dzia³aj± jak zamkniêcia (closures) w odniesieniu do zmiennych my(), to znaczy, zmiennych widocznych leksykalnie w bie¿±cym zakresie. Zamkniêcie jest pojêciem ze ¶wiata Lispa, mówi±cym, ¿e je¶li zdefiniujesz anonimow± funkcjê w konkretnym kontek¶cie leksykalnym, to bêdzie ona dzia³aæ w tym kontek¶cie nawet je¶li zosta³a wywo³ana poza nim.
Mówi±c po ludzku, jest to zabawny sposób przesy³ania argumentów do procedury zarówno gdy j± definiujesz jak i wtedy gdy j± wywo³ujesz. Przydaje siê to do tworzenia ma³ych fragmentów kodu do pó¼niejszego uruchamiania, jak np. wywo³ania wsteczne (callbacks). Przy ich pomocy mo¿esz robiæ nawet rzeczy zorientowane obiektowo, choæ Perl zapewnia ju¿ odmienny mechanizm operowania obiektami ---patrz podrêcznik perlobj(1).
Mo¿esz równie¿ my¶leæ o zamkniêciach jak o sposobie pisania szablonów bez u¿ywania eval. (Faktycznie, w wersji 5.000, eval by³o jedyn± metod± uzyskania zamkniêæ. Je¶li pos³ugujesz siê zamkniêciami, mo¿esz potrzebowaæ ``require 5.001''.)
A to ma³y przyk³ad tego, jak dzia³aj± zamkniêcia:
sub newprint { my $x = shift; return sub { my $y = shift; print "$x, $y!\n"; }; } $h = newprint("Howdy"); $g = newprint("Greetings");
# czas mija...
&$h("world"); &$g("earthlings");
Drukuje toHowdy, world! Greetings, earthlings!
Zwróæ uwagê szczególnie na to, ¿e $x nadal odnosi siê do warto¶ci przes³anej do newprint(), mimo ¿e zmienna ``my $x'' pozornie wysz³a poza swój zakres, w momencie gdy wywo³ano anonimow± procedurê. O to w³a¶nie chodzi w zamkniêciu.Przy okazji: odnosi siê do tylko do zmiennych leksykalnych. Zmienne dynamiczne dzia³aj± nadal tak jak zawsze. Zamkniêcie nie jest czym¶, o co musia³aby siê martwiæ wiêkszo¶æ programistów Perla.
- 5.
- Odwo³ania czêsto zwracane s± przez specjalne procedury zwane konstruktorami. Obiekty w Perlu s± po prostu odwo³aniami do specjalnego rodzaju obiektu, który wie z którym pakietem jest zwi±zany. Konstruktory s± specjalnymi procedurami, które wiedz± jak utworzyæ to powi±zanie. Robi± to zaczynaj±c od zwyk³ego odwo³ania, i pozostaje ono zwyk³ym odwo³aniem nawet wtedy gdy jest równocze¶nie obiektem. Konstuktory czêsto nazywane s± new() i wywo³ywane nie wprost:
$objref = new Psisko (Ogon => 'krótki', Uszy => 'd³ugie');
Ale nie musz± byæ:$objref = Psisko->new(Ogon => 'krótki', Uszy => 'd³ugie');
use Term::Cap; $terminal = Term::Cap->Tgetent( { OSPEED => 9600 });
use Tk; $main = MainWindow->new(); $menubar = $main->Frame(-relief => "raised", -borderwidth => 2)
- 6.
- Odwo³ania odpowiedniego typu mog± byæ powo³ywane do istnienia je¶li dereferencjonujesz je w kontek¶cie zak³adaj±cym, ¿e istniej±. Poniewa¿ jeszcze nie mówili¶my o dereferencji, nie mo¿emy na razie pokazaæ przyk³adów.
- 7.
- Odwo³anie mo¿e byæ utworzone przy pomocy specjalnej sk³adni, uroczo zwanej sk³adni± *foo{CO¦}. *foo{CO¦} zwraca odwo³anie do przegródki CO¦ w *foo (które jest pozycj± w tablicy symboli przechowuj±c± wszystko znane jako foo.)
$scalarref = *foo{SCALAR}; $arrayref = *ARGV{ARRAY}; $hashref = *ENV{HASH}; $coderef = *handler{CODE}; $ioref = *STDIN{IO}; $globref = *foo{GLOB};
Wszystkie powy¿sze wyra¿enia s± oczywiste, z wyj±tkiem *foo{IO}. Zwraca ono uchwyt IO, u¿ywany jako uchwyt pliku (patrz opis open w podrêczniku perlfunc(1)), gniazdo (opis socket oraz socketpair w perlfunc(1)) lub uchwyt katalogu (opendir w perlfunc(1)). Dla zgodno¶ci z poprzednimi wersjami Perla, *foo{UCHWYTPLIKU} jest synonimem *foo{IO}.*foo{CO¦} zwraca undef je¶li dane CO¦ jeszcze nie by³o u¿ywane, z wyj±tkiem dla skalarów. Je¶li nie u¿ywano jeszcze $foo, *foo{SKALAR} zwraca odwo³anie do anonimowego skalara. W przysz³ych wersjach mo¿e siê to zmieniæ.
*foo{IO} jest alternatyw± dla mechanizmu \*UCHWYTU opisanego w sekcji Typeglobs and Filehandles podrêcznika perldata(1), a s³u¿±cego do przesy³ania uchwytów plików do i z procedur lub przechowywania w wiêkszych strukturach danych. Jego wad± jest to, ¿e nie utworzy za Ciebie nowego uchwytu pliku. Zalet± za¶, ¿e nie ryzykujesz wiêcej ni¿ zamierza³e¶ przy przypisaniem typeglob, choæ je¶li wykonasz przypisanie do skalara zamiast do typeglob, to te¿ dobrze.
splutter(*STDOUT); splutter(*STDOUT{IO});
sub splutter { my $fh = shift; print $fh "her um well a hmmm\n"; }
$rec = get_rec(*STDIN); $rec = get_rec(*STDIN{IO});
sub get_rec { my $fh = shift; return scalar <$fh>; }
Pos³ugiwanie siê odwo³aniami
To tyle o tworzeniu odwo³añ. Teraz pewnie nie mo¿esz siê doczekaæ wiedzy jak pos³ugiwaæ siê odwo³aniami, by móc wróciæ do swych le¿±cych od³ogiem danych. Oto kilka podstawowych sposobów.- 1.
- Wszêdzie, gdzie postawi³by¶ identyfikator (lub ³añcuch identyfikatorów) jako czê¶æ nazwy zmiennej czy procedury, mo¿esz zast±piæ identyfikator prost± zmienn± skalarn± zawieraj±c± odwo³anie poprawnego typu:
$bar = $$scalarref; push(@$arrayref, $nazwapliku); $$arrayref[0] = "styczeñ"; $$hashref{"KLUCZ"} = "WARTO¦Æ"; &$coderef(1,2,3); print $globref "wynik\n";
Wa¿ne jest, by zrozumieæ, ¿e nie NIE wykonujemy tu specjalnie dereferencji $arrayref[0] czy $hashref{"KLUCZ"}. Dereferencja zmiennej skalarnej odbywa siê PRZED przeszukaniem klucza (indeksu tablicy). Wszystko bardziej skomplikowane ni¿ dereferencja prostej zmiennej skalarnej wymaga u¿ycia ni¿ej opisanych metod 2 lub 3. Jednak okre¶lenie ``prosty skalar'' obejmuje te¿ identyfikator, który sam u¿ywa rekurencyjnie metody 1. Zatem poni¿sze drukuje ``witaj''.$refrefref = \\\"witaj"; print $$$$refrefref;
- 2.
- Wszêdzie, gdzie postawi³by¶ identyfikator (lub ³añcuch identyfikatorów) jako czê¶æ nazwy zmiennej czy procedury, mo¿esz zast±piæ identyfikator BLOKiem zwracaj±cym odwo³anie poprawnego typu. Inaczej mówi±c, poprzednie przyk³ady mog± zostaæ zapisane tak:
$bar = ${$scalarref}; push(@{$arrayref}, $nazwapliku); ${$arrayref}[0] = "styczeñ"; ${$hashref}{"KLUCZ"} = "WARTO¦Æ"; &{$coderef}(1,2,3); $globref->print("wynik\n"); # je¶li za³adowano IO::Handle
Niew±tpliwie, u¿ycie nawiasów klamrowych w tym przypadku nie jest zbyt m±dre, ale BLOK mo¿e zawieraæ dowolne wyra¿enie, w szczególno¶ci wyra¿enia indeksowane:&{ $dispatch{$index} }(1,2,3); # wywo³aj w³a¶ciw± obs³ugê
Z powodu mo¿liwo¶ci pomijania nawiasów klamrowych dla prostych przypadków $$x, ludzie czêsto pope³niaj± b³±d postrzegania symboli dereferencji jako prawdziwych operatorów i zastanawiaj± siê nad ich priorytetem. Gdyby nimi by³y, móg³by¶ u¿ywaæ zwyk³ych nawiasów zamiast klamrowych. Tak jednak nie jest. Rozwa¿ poni¿sz± ró¿nicê: przypadek 0 jest skrócon± wersj± przypadku 1, NIE przypadku 2:$$hashref{"KLUCZ"} = "WARTO¦Æ"; # przypadek 0 ${$hashref}{"KLUCZ"} = "WARTO¦Æ"; # przypadek 1 ${$hashref{"KLUCZ"}} = "WARTO¦Æ"; # przypadek 2 ${$hashref->{"KLUCZ"}} = "WARTO¦Æ"; # przypadek 3
Przypadek 2 jest równie¿ myl±cy, gdy¿ odnosi siê do zmiennej o nazwie %hashref, nie za¶ dereferencjonuje poprzez $hashref hasza, na który wydawa³oby siê wskazuje skalar. To robi przypadek 3. - 3.
- Wywo³ania procedur i poszukiwanie poszczególnych elementów tablic pojawiaj± siê wystarczaj±co czêsto, by zastosowanie do nich metody 2 sta³o siê niewygodne. Jako formê "os³odzenia sk³adni", przyk³ady z metody 2 mo¿na zapisaæ:
$arrayref->[0] = "styczeñ"; # element tablicy $hashref->{"KLUCZ"} = "WARTO¦Æ"; # element hasza $coderef->(1,2,3); # wywo³anie procedury
Lewa strona strza³ki mo¿e byæ dowolnym wyra¿eniem zwracaj±cym odwo³anie, ³±cznie z uprzedni± dereferencj±. [U³atwia to operowanie odwo³aniami do zmiennych zawieraj±cych kolejne odwo³ania, jak poni¿ej]. Zauwa¿, ¿e $array[$x] NIE jest tu tym samym co $array->[$x]:$array[$x]->{"foo"}->[0] = "styczeñ";
Jest to jeden z przypadków wspomnianych wcze¶niej, gdzie odwo³ania zaistniej±, gdy zostan± u¿yte w kontek¶cie l-warto¶ci. Przed t± instrukcj±, element $array[$x] móg³ byæ niezdefiniowany. W takim przypadku, jest on definiowany automatycznie z nadaniem mu warto¶ci -- odwo³ania do hasza, tak ¿e mo¿emy poszukiwaæ w haszu elementu o kluczu "foo". Podobnie klucz $array[$x]->{"foo"} zostanie automatycznie zdefiniowany z równoczesnym nadaniem warto¶ci -- odwo³ania do tablicy, zatem bêdzie mo¿na w niej odnale¼æ [0]. Proces ten zwany jest autovivification (automatyczne o¿ywianie).Jeszcze jedno. POMIÊDZY indeksami umieszczonymi w nawiasach klamrowych strza³ka jest opcjonalna, zatem mo¿emy skróciæ powy¿szy zapis do:
$array[$x]{"foo"}[0] = "styczeñ";
Co, w szczególnym przypadku dzia³ania tylko na zwyk³ych tablicach, daje tablice wielowymiarowe z zapisem jak w C:$score[$x][$y][$z] += 42;
No dobrze, tak naprawdê, nie ca³kiem jak tablice w C. C nie wie, jak poszerzaæ tablice na ¿±danie. Perl to potrafi. - 4.
- Je¿eli odwo³anie jest odwo³aniem do obiektu, to prawdopodobnie istniej± metody dostêpu do wskazywanych przez nie rzeczy, i powiniene¶ zapewne z nich skorzystaæ, chyba ¿e jeste¶ w pakiecie klasy definiuj±cej metody tego obiektu i pracujesz nad nimi. Inaczej mówi±c, b±d¼ tak dobry i nie naruszaj hermetyzacji bez istotnego powodu. Perl nie wymusza hermetyzacji. Nie jeste¶my tu totalitarystami. Oczekujemy jednak zachowania podstawowych zasad uprzejmo¶ci.
Mo¿na pos³u¿yæ siê operatorem ref() do stwierdzenia, na jaki typ rzeczy wskazuje odwo³anie. Zobacz podrêcznik perlfunc(1).
Operator bless() mo¿e byæ u¿ywany do powi±zania obiektu, na który wskazuje odwo³anie, z pakietem funkcjonuj±cym jako klasa obiektowa. Zobacz podrêcznik perlobj(1).
Typeglob mo¿e byæ dereferencjowane w ten sam sposób jak odwo³anie, gdy¿ sk³adnia dereferencji zawsze wskazuje na po¿±dany rodzaj odwo³ania. Zatem ${*foo} i ${\$foo} wskazuj± na tê sam± zmienn± skalarn±.
A oto sztuczka do interpolacji wywo³ania procedury w ³añcuchu:
print "Procedura mysub tym razem zwróci³a @{[mysub(1,2,3)]} .\n";Dzia³a to w tak, ¿e gdy @{...} znalezione zostanie wewn±trz ³añcucha w cudzys³owach to zostanie potraktowane jako blok. Blok ten tworzy odwo³anie do jednoelementowej anonimowej tablicy zawieraj±cej wynik wywo³ania mysub(1,2,3) [odwo³anie to utworzone bêdzie dziêki nawiasom kwadratowym]. Zatem ca³y blok zwraca odwo³anie do tablicy, która nastêpnie podlega dereferencji powodowanej przez @{...}. Jej warto¶æ, jako umieszczona w ³añcuchu w cudzys³owach podlega interpolacji w napis. Takie szykany przydaj± siê tak¿e w dowolnych wyra¿eniach:
print "That yields @{[$n + 5]} widgets\n";
Odwo³ania symboliczne
Powiedzieli¶my, ¿e niezdefiniowane cele odwo³ania w razie potrzeby zaistniej± [podczas dereferencji]. Nie mówili¶my jednak, co siê dzieje, gdy warto¶æ u¿yta jako odwo³anie jest ju¿ zdefiniowana, ale NIE JEST odwo³aniem sta³ym. Je¿eli u¿yjesz odwo³ania w takim przypadku, to bêdzie ono potraktowane jak odwo³anie symboliczne. To znaczy, warto¶ci± skalara zostanie NAZWA zmiennej a nie bezpo¶rednie dowi±zanie do (byæ mo¿e anonimowej) warto¶ci.Niektórzy czêsto spodziewaj± siê, ¿e dzia³a to jako¶ tak. I rzeczywi¶cie.
$name = "foo"; $$name = 1; # ustawia $foo ${$name} = 2; # ustawia $foo ${$name x 2} = 3; # ustawia $foofoo $name->[0] = 4; # ustawia $foo[0] @$name = (); # czy¶ci @foo &$name(); # wywo³uje &foo() (jak w Perl 4) $pack = "THAT"; ${"${pack}::$name"} = 5; # ustawia $THAT::foo bez rozwiniêcia(eval)Jest to bardzo silne narzêdzie, ale nieco niebezpieczne, gdy¿ mo¿liwe jest, ze szczerym zamiarem u¿ycia odwo³ania sta³ego, przypadkowe u¿ycie symbolicznego. Mo¿esz siê przed tym uchroniæ pisz±c:
use strict 'refs';a dla reszty otaczaj±cego bloku bêd± dozwolone tylko odwo³ania sta³e. Wewnêtrzny blok mo¿e siê temu sprzeciwiæ przy pomocy
no strict 'refs';Dla odwo³añ symbolicznych widoczne s± tylko zmienne pakietu (globalne, nawet je¶li lokalnie). Zmienne leksykalne (deklarowane przy pomocy my()) nie zawieraj± siê w tablicy symboli, zatem s± niewidoczne dla tego mechanizmu. Na przyk³ad:
local $wartosc = 10; $ref = "wartosc"; { my $wartosc = 20; print $$ref; }Nadal bêdzie drukowaæ 10, a nie 20. Pamiêtaj, ¿e local() dzia³a na zmienne pakietu, które dla samego pakietu wszystkie s± ``globalne''.
Odwo³ania niezbyt symboliczne
Now± cech± poprawiaj±c± czytelno¶æ, wprowadzon± w perlu wersji 5.001, jest to, ¿e nawiasy wokó³ odwo³ania symbolicznego zachowuj± siê jak znaki cudzys³owu, czyli tak, jakby zawsze zawiera³y wewn±trz ³añcuch. To znaczy, ¿e$push = "pop on "; print "${push}over";mia³o zawsze znaczenie wydrukowania ``pop on over'', bez wzglêdu na fakt, ¿e "push" jest s³owem zarezerwowanym. Zosta³o to uogólnione tak, by dzia³aæ równie¿ poza cudzys³owami, zatem
print ${push} . "over";a nawet
print ${ push } . "over";maj± ten sam rezultat. (Spowodowa³oby to b³±d sk³adni w Perlu 5.000, choæ Perl 4 dopuszcza co¶ takiego w postaci bez odstêpów.) Zauwa¿, ¿e konstrukcja ta nie nie jest uwa¿ana za odwo³anie symboliczne gdy u¿ywasz strict refs:
use strict 'refs'; ${ bareword }; # dobrze, znaczy $bareword. ${ "bareword" }; # b³±d, odwo³anie symboliczne.Podobnie, z powodu wszelkiego indeksowania przy pomocy pojedynczych s³ów, zastosowali¶my tê sam± regu³ê do ka¿dego z go³ych s³ów u¿ytego do indeksowania hasza. Zatem teraz, zamiast
$array{ "aaa" }{ "bbb" }{ "ccc" }mo¿esz napisaæ po prostu
$array{ aaa }{ bbb }{ ccc }i nie martwiæ siê o to, czy indeksy s± s³owami zarezerwowanymi. W tych rzadkich przypadkach, gdy chcesz zrobiæ co¶ w rodzaju
$array{ shift }mo¿esz wymusiæ interpretacjê s³owa jako zarezerwowanego dodaj±c cokolwiek, co zrobi zeñ wiêcej ni¿ go³e s³owo:
$array{ shift() } $array{ +shift } $array{ shift @_ }Prze³±cznik -w bêdzie Ciê ostrzega³, je¶li zinterpretuje s³owo zarezerwowane jako ³añcuch. Nie bêdzie jednak ostrzega³ o u¿yciu s³ów pisanych ma³ymi literami, gdy¿ ³añcuch jest faktycznie cytowany.
Pseudo-hasze: U¿ywanie tablicy jak hasza
OSTRZE¯ENIE: Niniejsza sekcja opisuje cechê eksperymentaln±. W przysz³ych wersjach szczegó³y mog± ulec zmianie bez powiadomienia.Pocz±wszy od Perla 5.005 mo¿esz w pewnych kontekstach pos³ugiwaæ siê odwo³aniem do tablicy, mimo ¿e normalnie wymagaj± one odwo³ania do hasza. Pozwala to na dostêp do elementów tablicy przy u¿yciu nazw symbolicznych, tak jakby by³y one polami struktury.
¯eby to zadzia³a³o tablica musi zawieraæ dodatkow± informacjê. Pierwszym elementem tablicy powinno byæ odwo³anie do hasza odwzorowuj±cego nazwy pól na indeksy tablicy. Oto przyk³ad:
$struct = [{foo => 1, bar => 2}, "FOO", "BAR"];
$struct->{foo}; # to samo, co $struct->[1], tj. "FOO" $struct->{bar}; # to samo, co $struct->[2], tj. "BAR"
keys %$struct; # zwróci ("foo", "bar") w jakiej¶ kolejno¶ci values %$struct; # zwróci ("FOO", "BAR") w jakiej¶ kolejno¶ci
while (my($k,$v) = each %$struct) { print "$k => $v\n"; }Je¶li spróbujesz usun±æ klucze z takiego pseudo-hasza lub bêdziesz próbowa³ siêgn±æ do nieistniej±cych pól, perl zg³osi wyj±tek. W celu poprawy wydajno¶ci, Perl mo¿e te¿ wykonaæ na etapie kompilacji t³umaczenie nazw pól na odpowiadaj±ce im indeksy tablicy dla opisanych odwo³añ. Patrz podrêcznik fields(3).
Szablony funkcji
Jak wyja¶niono powy¿ej, zamkniêcie jest anonimow± funkcj± z dostêpem do zmiennych leksykalnych widocznych podczas jej kompilacji. Zachowuje ona dostêp do tych zmiennych nawet wtedy, gdy jest wykonywana pó¼niej, tak jak funkcja obs³ugi sygna³u (signal handler) czy wywo³anie wsteczne Tk.Pos³ugiwanie siê zamkniêciem jako szablonem funkcji umo¿liwia tworzenie wielu podobnie dzia³aj±cych funkcji. Za³ó¿my, ¿e potrzebujesz funkcji o nazwach pochodz±cych od ró¿nych kolorów zmieniaj±cych czcionkê HTML.
print "Hej, ", red("uwa¿aj"), "na to ", green("¶wiat³o");Funkcje red() i green() bêd± bardzo podobne. By je stworzyæ, przypiszemy zamkniêcie do typeglob nazwy funkcji, któr± próbujemy skonstruowaæ.
@kolory = qw(red blue green yellow orange purple violet); for my $nazwa (@kolory) { no strict 'refs'; # pozwól na operowanie tablic± symboli *$nazwa = *{uc $nazwa} = sub { "<FONT COLOR='$nazwa'>@_</FONT>" }; }Teraz wszystkie te funkcje bêd± istnieæ niezale¿nie od siebie. Mo¿esz wywo³ywaæ red(), RED(), blue(), BLUE(), green(), etc. Technika ta zarówno skraca czas kompilacji jak i zmniejsza zu¿ycie pamiêci, jest te¿ mniej nara¿ona na b³êdy, gdy¿ kontrola sk³adni odbywa siê podczas kompilacji. Istotne jest, by wszelkie zmienne w anonimowej procedurze by³y zmiennymi leksykalnymi by stworzyæ poprawne zamkniêcie. Z tego powodu u¿yto my dla zmiennej steruj±cej pêtli.
Jest to jedno z jedynych miejsc, gdzie dostarczenie prototypu do zamkniêcia ma sens. Je¶li chcia³by¶ narzuciæ kontekst skalarny dla argumentów powy¿szych, przyk³adowych funkcji (pewnie nie najlepszy pomys³ w tym przypadku), mo¿esz zapisaæ to inaczej:
*$nazwa = sub ($) { "<FONT COLOR='$nazwa'>$_[0]</FONT>" };Jednak¿e, poniewa¿ sprawdzanie protypów odbywa siê podczas kompilacji, powy¿sze przypisanie zostanie wykonane za pó¼no, by by³o przydatne. Móg³by¶ to obej¶æ przez w³o¿enie ca³ej pêtli przypisañ do wnêtrza bloku BEGINu, wymuszaj±c wykonanie go w czasie kompilacji.
Dostêp do zmiennych leksykalnych zmieniaj±cych typ --- jak te w pêtli for powy¿szego przyk³adu- dzia³a wy³±cznie z zamkniêciami, a nie z procedurami w ogóle. Zatem w przypadku ogólnym, procedury nazwane nie zagnie¿d¿aj± siê prawid³owo, choæ robi± to procedury anonimowe. Je¶li nawyk³e¶ do u¿ywania zagnie¿d¿onych procedur z w³asnymi prywatnymi zmiennymi w innych jêzykach programowania, to w Perlu bêdziesz musia³ nad trochê popracowaæ. Intuicyjna metoda kodowania tego typu rzeczy spowoduje tajemnicze ostrze¿enia ``will not stay shared'' (nie pozostanie wspólne). To, na przyk³ad, nie zadzia³a:
sub zewn { my $x = $_[0] + 35; sub wewn { return $x * 19 } # ¬LE return $x + wewn(); }Obej¶cie jest nastêpuj±ce:
sub zewn { my $x = $_[0] + 35; local *wewn = sub { return $x * 19 }; return $x + wewn(); }Teraz wewn() mo¿e byæ wywo³ana tylko z wnêtrza zewn(), z powodu tymczasowego przypisania zamkniêcia (procedury anonimowej). Ale kiedy jest wywo³ywana, to ma zwyk³y dostêp do zmiennej leksykalnej $x z zakresu procedury zewn().
Ma to interesuj±cy skutek tworzenia funkcji lokalnych wzglêdem innych funkcji, co normalnie nie jest obs³ugiwane w Perlu.
OSTRZE¯ENIE
Nie mo¿esz (w u¿yteczny sposób) pos³u¿yæ siê odwo³aniem jako kluczem hasza. Zostanie ono zamienione na ³añcuch:$x{ \$a } = $a;Je¶li spróbujesz zdereferencjonowaæ klucz, nie otrzymasz odwo³ania sta³ego a ³añcuch i nie uzyskasz tego, co próbowa³e¶. W zamian mo¿na napisaæ co¶ podobnego do:
$r = \@a; $x{ $r } = $r;a nastêpnie u¿yæ values(), co zwróci rzeczywiste odwo³ania, zamiast u¿ycia keys(), gdy¿ klucze odwo³aniami nie bêd±.
Standardowy modu³ Tie::RefHash umo¿liwia wygodny sposób obej¶cia tego problemu.
ZOBACZ TAK¯E
Poza oczywist± dokumentacj±, pouczaj±ca mo¿e byæ analiza kodu ¼ród³owego. Kilka raczej patologicznych przyk³adów u¿ycia odwo³añ znajdziesz w te¶cie regresji t/op/ref.t w katalogu ¼róde³ Perla.Zobacz równie¿ podrêczniki perldsc(1) i perllol(1), opisuj±ce pos³ugiwanie siê odwo³aniami do tworzenia z³o¿onych struktur danych, oraz perltoot(1), perlobj(1) i perlbot(1) opisuj±ce ich u¿ycie do tworzenia obiektów.
Contenus ©2006-2024 Benjamin Poulain
Design ©2006-2024 Maxime Vantorre