perlref

Autres langues

Langue: pl

Autres versions - même langue

Version: perl 5.005, patch 03 (openSuse - 09/10/07)

Section: 1 (Commandes utilisateur)

NAZWA

perlref - odwo³ania i zagnie¿d¿one struktury danych w Perlu

UWAGA

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 to

    Howdy, 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.