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.

PERL’e 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


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";
 

 

Į turinį