Provided by: manpages-pl_0.5-1_all 

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
Uwaga! To tłumaczenie może być nieaktualne!
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.
INFORMACJE O TŁUMACZENIU
Powyższe tłumaczenie pochodzi z nieistniejącego już Projektu Tłumaczenia Manuali i może nie być aktualne.
W razie zauważenia różnic między powyższym opisem a rzeczywistym zachowaniem opisywanego programu lub
funkcji, prosimy o zapoznanie się z oryginalną (angielską) wersją strony podręcznika za pomocą polecenia:
man --locale=C 1 perlref
Prosimy o pomoc w aktualizacji stron man - więcej informacji można znaleźć pod adresem
http://sourceforge.net/projects/manpages-pl/.
3rd Berkeley Distribution perl 5.005, patch 03 PERLREF(1)