Nuorodos ir sudėtingos duomenų struktūros |
Nuorodos
Visi programos kintamieji identifikuojami ne tik pagal savo vardą bet ir atminties adresą. Nuoroda (reference) į kintamąjį saugo to kintamojo atminties adresą. Žinant atminties adresą, visada galima nuskaityti, kas yra saugoma tuo adresu. Pagrindinė nuorodų panaudojimo sritis sudėtingų duomenų struktūrų kūrimas, pavyzdžiui n-mačiai masyvai, objektai ir t.t.
PERLe nuoroda tai skaliaras, kuris bendru atveju gali būti surištas su bet kokio tipo duomenimis. Taigi nuorodos tipas apsprendžiamas pagal tai, į kokio tipo duomenis nuoroda sukurta. Galima sukurti ir nuorodą į nuorodą bei nuorodą į typeglob tipo duomenis. typeglob - tai PERL vidinis duomenų tipas, naudojamas apibrėžti skirtingą tipą, bet vienodus vardus turinčius kintamuosius. Nuorodos tipą galima sužinoti funkcijos ref() pagalba, kuri grąžina tokius rezultatus:
REF | nuoroda į nuorodą |
SCALAR | nuoroda į skaliarą |
ARRAY | nuoroda į masyvą |
HASH | nuoroda į asociatyvinį masyvą |
CODE | nuoroda į paprogramę |
GLOB | nuoroda į typeglob tipo kintamąjį |
PERL'e nuorodos gali būti dviejų tipų: standžios (hard references ) ir simbolinės (symbolic references). Šie nuorodų tipai glaudžiai siejami su UNIX failinėse sistemose naudojamais ryšių tipais (hard & soft link). Standžios nuorodos - tai skaliarinis dydis, saugantis atminties ląstelės adresą, kuriuo gali būti pasiekiami duomenys. Simbolinė nuoroda - tai skaliarinis kintamasis, kuriame saugomas kito kintamojo vardas. Dažniausiai naudojamos standžios nuorodos. Atminties adresas, kuriame saugomi duomenys gali turėti kelias standžias nuorodas, kurios yra lygiavertes, todėl duomenys ištrinami tik tuomet, kai panaikinama paskutinė standi nuoroda.
Galimi nuorodų sukūrimo būdai
Operacija "\" sukuria nuorodą į kintamąjį, kuris
eina po "\" simbolio. Tai gali būti bet kokio tipo kintamasis, pavyzdžiui:
$scalarref = \$foo;
$constref = \186_282.42;
$arrayref = \@ARGV;
$hashref = \%ENV;
$func_ref = \&handler;
$globref = \*STDOUT;
Nuoroda į anoniminį masyvą
naudojant [ ]. Tokiu būdu sukurimas masyvas be pavadinimo bei nuoroda į jį,
pavyzdžiui:
$arrayref = [1, 2, 3];
Nuoroda į anoniminį asociatyvinį
masyvą naudojant { }, pavyzdžiui:
$hashref = {
'Adam' => 'Eve',
'Clyde' => 'Bonnie',
};
Galima sukurti nuorodą į anoniminę
paprogramę naudojant raktinį žodį sub be paprogramės pavadinimo, payzdžiui:
$func_ref = sub { print
"Labas!\n" };
Nuo PERL v.5.0 ši kalba laikoma
objektiškai orientuota. Objektai kuriami konstruktoriaus pagalba ir pasiekiami
tik per nuorodas.
obj_ref
= new Doggie Tail => 'short', Ears => 'long';
# arba
$obj_ref = Doggie->new(Tail => 'short',
Ears => 'long');
Nuorodos į
typeglob tipo
kintamuosius (VISŲ tipų kintamieji vienodu vardu) kuriami naudojant "*" simbilį, pavyzdžiui:
$scalarref = *a{SCALAR};
$arrayref = *a{ARRAY};
$hashref =
*a{HASH};
$func_ref = *a{CODE};
$globref = *a{GLOB};
Nuorodų panaudojimas
Naudojant nuorodas, visada iškyla poreikis gauti duomenis, kurių atminties adresą saugo nuoroda (angl. dereference). Tam tikslui naudojamos įvairios sintaksinės konstrukcijos, kartais labai sudėtingos. Iš esmės sintaksė priklauso nuo nuorodos tipo.
Paprastas skaliarinis kintamasis
Jei nuoroda yra paprastas skaliarinis kintamasis (be indekso), tai norint pasiekti duomenis, reikia vietoj objekto vardo naudoti skaliarinį kintamąjį, pavyzdžiui:
$foo = "du vilkai"; $scalar_ref = \$foo; $volf_model = $$scalar_ref; # $volf_model dabar "du vilkai"
Kiti pavyzdžiai:
$bar = $$scalar_ref;
@array = @$array_ref;
%hash = %$hash_ref;
$$arrayref[0] = "January";
$$hashref{"KEY"} = "VALUE";
&$coderef(1,2,3);
print $globref "output\n";
Blokai
Jei nuoroda yra masyvo arba asociatyvinio masyvo elementas, tai pasiekiant duomenis, reiktų figūriniais skliaustais {} apskliausti nuorodą ir ją naudoti kintamojo varde, pavyzdžiui:
$bar = ${$scalar_ref};
${$arrayref}[0] = "January";
${$hashref}{"KEY"} = "VALUE";
&{$coderef}(1,2,3);
Operacija ->
Apskliaudžiant nuorodas figūriniais skliaustais, gali būti sukurtos gremėzdiškos, sunkiai skaitomos blokinės išraiškos. Todėl vietoj figūrinių skliaustų gali būti naudojama strėlytė ->. Kairėjė jos pusėje gali būti rašoma nuoroda į masyvą arba asociatyvinį masyvą, dešinėje - masyvo indeksas arba raktas, pavyzdžiui:
${
$arrayref }[0] = "January"; #tas pats,
kas žemiau
$arrayref->[0] = "January";
#tas pats, kas aukščiau
${ $hashref }{KEY} = "major";
#tas pats, kas žemiau
$hashref->{KEY} = "major";
#tas pats, kas aukščiau
Kitas pavyzdys:
$array_ref[0] = \@myarray1;
#sukuriama nuoroda į
masyvą
$array_ref[1] = \@myarray2;
#sukuriama nuoroda į
asociatyvinį masyvą
print (Masyvo myarray1 pirmas narys = $array_ref[0]->[0]);
print (Masyvo myarray2 antras narys = $array_ref[1]->[1]);
Simbolinės nuorodos
Simbolinė nuoroda - tai skaliarinis kintamasis, kurio reikšmė kito kintamojo pavadinimas. Su šiuo kintamuoju atliekami visi tie patys veiksmai, kaip ir su nuoroda.
$name = "bam";
$$name = 1;
# Priskiriam $bam = 1
${$name} = 2;
# Priskiriam $bam = 2
${$name x 2} = 3;
# Priskiriam $bambam = 3
@$name = (1,2,3);
# Kuriamas masyvas @bam
%$name = ("one"=>1,"two"=>2,"three"=>3);
# Kuriamas asociatyvinis masyvas %bam
Simbolinės nuorodos yra painios, todėl dažnai siūloma, jei tai įmanoma, jų nenaudoti. Galima net uždrausti naudoti simbolines nuorodas bloko ribose:
use strict 'refs';
Svarbu suprasti skirtumą tarp sekančių dviejų eilučių:
${identifier}; # tas pats kaip $identifier ${"identifier"}; # tas pats kaip $identifier, tačiau tai ssurišta su simboline nuoroda.
Sudėtingos duomenų struktūros
PERL standartinių duomenų struktūrų sąraše nerasite tokių struktūrų kaip dvimatis ar n-matis masyvas, struktūros ar objektai. Tačiau be jų dažnai neišsiversi, todėl nuorodų pagalba yra formuojami išvestiniai duomenų tipai, leidžiantis sukurti bet kokias duomenų struktūras.
Masyvų masyvas
Šis išvestinis duomenų tipas naudojamas, norint sukurti dvimatį, trimatį ar n-matį masyvą. Tokio masyvo elementais būna anoniminiai masyvai arba nuorodos į masyvus. Jei norėtume /etc/passwd failą nuskaityti į atmintį, tam labai tiktų išvestinė duomenų struktūra masyvų masyvas. Pavyzdžiai:
#Masyvų masyvas formuojamas
@draugai = (
[ "fred", "barney" ],
[ "george", "jane", "elroy" ],
[ "jone", "marge", "bart" ],
);
#Masyvų masyvas formuojamas, nuskaitant iš failo
while ( <> ) {
push @draugai, [ split ];
}
#Masyvų masyvas formuojamas, iškviečiant funkciją
for $i ( 1 .. 10 ) {
$draugai[$i] = [ funcija($i) ];
#arba $draugai[$i] = &$func_ref($i);
}
#Masyvų masyvas formuojamas, per tarpinį kintamąjį
for $i ( 1 .. 10 ) {
@tmp = funkcija($i);
$draugai[$i] = [ @tmp ];
}
#Masyvų masyvo papildymas dar viena eilute push @{ $draugai[0] }, "wilma", "betty";
#Dvimačio masyvo spausdinimas
for $i ( 0 .. $#draugai ) {
for $j ( 0 .. $#{$draugai[$i]} ) {
print "Elementas $i $j is $draugai[$i][$j]\n";
} }
Asociatyvinių masyvų masyvas
Ši duomenų struktūra apibrėžiama kaip įrašų masyvas, kuriame kiekvienas įrašas asociatyvinis masyvas, pavyzdžiui:
@Hash_arr = ( { draugas => "fred", priesas => "barney", }, { as => "george", tu => "jane", jis => "elroy", }, { mes => "homer", jus => "marge", jie => "bart", }, );
#
Inicializavimas nuskaitant failą
# formatas: draugas = barney
priesas = jone
while ( <> ) {
$rec = {};
for $field ( split ) {
($key, $value) = split /=/, $field;
$rec->{$key} = $value;
}
push @Hash_arr, $rec;
}
# Reikšme priskiriama elementui
$ Hash_arr[0]{lead} = "fred";
# Kitas elementas
$ Hash_arr [1]{lead} =~ s/(\w)/\u$1/;
# Informacijos išvedimas
for $i ( 0 .. $# Hash_arr ) {
print "$i yra { ";
for $role ( keys %{ $ Hash_arr [$i] } ) {
print "$role=$ Hash_arr [$i]{$role} ";
}
print "}\n";
}
# Informacijos išvedimas (kitas variantas)
for $i ( 0 .. $# Hash_arr ) {
for $role ( keys %{ $ Hash_arr [$i] } ) {
print "elementas $i $role yra $ Hash_arr [$i]{$role}\n";
}
}
Masyvų asociatyviniai masyvai
Ši duomenų struktūra naudojama tuomet, kai norima dvimačiame masyve, atskirus masyvus identifikuoti ne pagal numerį, o pagal raktą. Pavyzdys čia galėtų būti kalendorius, kuriame kiekvienas įrašas (masyvo elementas) atititinka tam tikrą mėnesį, o asociatyviniame masyve saugomos savaitės dienos ir jas atitinkančios mėnesio dienos:
%Kalendorius = ("Pirmadienis" => [(1,8,15,22,29)], "Antradienis" => [(2,9,16,22,30)] )
# Suformuojamas masyvų asociatyvinis masyvas %filmukai = ( Flintstones => [ "fred", "barney" ], Jetsons => [ "george", "jane", "elroy" ], Simpsons => [ "homer", "marge", "bart" ], );
#
Nuskaitome iš failo
formatu:
# flintstones: fred barney wilma dino
while ( <> ) {
next unless s/^(.*?):\s*//;
$filmukai{$1} = [ split ];
}
#
papildome masyvą
push @{ $filmukai{flintstones} }, "wilma", "betty";
Asociatyvinių masyvų asociatyviniai masyvai
Tai pati lanksčiausia PERL homogeninė duomenų struktūra, kurioje vietoje įpratinės asociatyvininio masyvo reikšmės yra kitas asociatyvinis masyvas, pavyzdžiui:
%HoH = ( Flintstones => { tevas => "fred", draugas => "barney", }, Jetsons => { tevas => "george", mama => "jane", vaikas => "elroy", }, Simpsons => { vyras => "homer", zmona => "marge", sunus => "bart", }, );
#
nuskaitymas iš failo formatu:
# Flintstones: tevas=fred draugas=barney
while ( <> ) {
next unless s/^(.*?):\s*//;
$who = $1;
for $field ( split ) {
($key, $value) = split /=/, $field;
$HoH{$who}{$key} = $value;
}
}
#
Elementui reikšmė priskiriama taip:
$HoH{flintstones}{wife} = "wilma";
#
Atspausdinamas visas masyvas
foreach $seima ( keys %HoH ) {
print "$seima: ";
foreach $role ( keys %{ $HoH{$seima} } ) {
print
"$role=$HoH{$seima}{$role} ";
}
print "\n";