Svet Perlu: 3. časť / Referencie a podprogramy

perl_logo.png Re­fe­ren­cie
Jed­ným zo zá­važ­ných ne­dos­tat­kov Per­lu bo­la do­ne­dáv­na ab­sen­cia po­dpo­ry kom­plexných dá­to­vých štruk­túr po­dob­ných pas­ca­lov­ským zá­zna­mom ale­bo štruk­tú­ram ja­zy­ka C. Vy­tvá­ra­nie viac­roz­mer­ných po­lí bo­lo za­ťa­že­né kom­pli­ko­va­ný­mi syn­tak­tic­ký­mi konštruk­cia­mi, kto­rých po­uží­va­nie zni­žo­va­lo či­ta­teľ­nosť kó­du a kto­ré ne­dis­po­no­va­li po­tre­bou flexibil­nos­ťou v sme­re po­dpo­ry ma­ni­pu­lač­ných fun­kcií. Perl už od pia­tej ver­zie v po­ra­dí im­ple­men­tu­je vy­so­ko flexibil­ný a vý­kon­ný re­fe­renč­ný mo­del, kto­rý je kon­cep­čne od­liš­ný od tra­dič­ných mo­de­lov po­uží­va­ných prog­ra­mo­va­cí­mi ja­zyk­mi.

Sym­bo­lic­ké re­fe­ren­cie a kon­ku­ren­čné mo­de­ly
Sym­bo­lic­ké re­fe­ren­cie sú de­fi­no­va­né ako iden­ti­fi­kač­né od­ka­zy na ob­jek­ty. Sym­bo­lic­ká re­fe­ren­cia ne­sie in­for­má­ciu o náz­ve iden­ti­fi­ká­to­ra re­fe­ren­čné­ho ob­jek­tu. Ich po­uží­va­nie de­monštru­je frag­ment (1), kto­rý de­fi­nu­je mno­ži­nu po­lí ska­lá­rov a jed­no „re­fe­ren­čné“ po­le uc­ho­vá­va­jú­ce náz­vy jed­not­li­vých po­lí. Ten­to prís­tup vy­uží­va inter­pre­te­ro­vý cha­rak­ter Per­lu, kto­rý do­vo­ľu­je jed­no­duc­hú im­ple­men­tá­ciu re­fe­ren­čné­ho mo­de­lu, za­lo­že­né­ho na sub­sti­tuč­nom prin­cí­pe, pri kto­rom je kon­krét­ny ná­zov ob­jek­tu za be­hu nah­ra­de­ný z od­po­ve­da­jú­cou hod­no­tou sym­bo­lic­kej re­fe­ren­cie. Pri­ra­de­nie na kon­ci frag­men­tu pris­tu­pu­je k pr­vku fik­tív­ne­ho dvoj­roz­mer­né­ho po­ľa fooArray na in­dexoch 1,1. Vý­raz (2) je inter­pre­to­va­ný ako sub­sti­tú­cia náz­vu da­né­ho po­ľa a je v ko­neč­nom dôs­led­ku vy­ko­na­ný ako (3). Mo­del sym­bo­lic­kých re­fe­ren­cií po­uží­va ta­buľ­ku sym­bo­lov. Sym­bo­lic­ké re­fe­ren­cie mô­žu od­ka­zo­vať len na ob­jek­ty ba­lí­ka. Pre­men­né dek­la­ro­va­né po­mo­cou my nie sú re­fe­ro­va­teľ­né.

(1) #par­ciál­ne po­lia ska­lá­rov tvo­ria­ce dru­hý roz­mer fik­tív­ne­ho po­ľa
    @fooArray0 = ("re­cord00", "re­cord01", "re­cord02");
    @fooArray1 = ("re­cord10", "re­cord11", "re­cord12");
    @fooArray2 = ("re­cord20", "re­cord21", "re­cord22");

    #re­fe­ren­čné po­le ob­sa­hu­jú­ce náz­vy par­ciál­nych po­lí
    @fooArray  = ("fooArray0", "fooArray1", "fooArray2");

    #pri­ra­de­nie pr­vku fik­tív­ne­ho po­ľa fooArray na in­dexoch 1,1
    $foo = ${$fooArray[1]}[1];

(2) $fooArray[1]
(3) $foo = ${$fooArray[1]}[1] <=> $foo = $fooArray1[1];

Al­ter­na­tív­nym rie­še­ním je mo­del emu­lo­va­nia uka­zo­va­te­ľov vy­uží­va­jú­ci je­di­né po­le ska­lá­rov, kto­ré­ho pr­vky ob­sa­hu­jú čias­tko­vé pr­vky ďal­šie­ho roz­me­ru, od­de­le­né „vhod­ným“ zna­kom. Ten­to po­stup je čas­to vý­hod­ný, pri­čom na dru­hej stra­ne je extra­ho­va­nie sa­mos­tat­ných pr­vkov po­ľa nie­ke­dy neú­nos­ne neob­rat­né. Prík­lad po­uži­tia toh­to mo­de­lu pri­ná­ša frag­ment (4). Čas­to po­uží­va­ný­mi fun­kcia­mi v kon­texte s emu­lo­va­ním uka­zo­va­te­ľov sú split a join.

(4)#ako "vhod­ný" od­de­ľo­vač bol zvo­le­ný znak "|"
   @fooArray = ("re­cord00|re­cord01", "re­cord01|re­cord01","re­cord02|re­cord01");

   for (@fooArray) {
      ($foo0, $foo1) = split(/\|/);
       print "$foo0 $foo1\n";
   }

Pre mno­hých ťaž­ko po­cho­pi­teľ­ným mo­de­lom je mo­del po­uží­va­jú­ci ty­peg­lo­by. Po­sled­né pri­ra­de­nie frag­men­tu (1) by bo­lo mož­né s vy­uži­tím ty­peg­lo­bov vy­jad­riť (5).

(5) *foo­Ty­peG­lob = $fooArray[1];
    $foo = $foo­Ty­peG­lob[1];

Pra­vé re­fe­ren­cie
Prív­las­tok „pra­vé“ som si vy­mys­lel, pre­to­že v an­glic­kej li­te­ra­tú­re sú pra­vé re­fe­ren­cie ozna­čo­va­né prív­las­tkom „hard“, kto­ré­ho po­uži­tie slo­ven­skom prek­la­de by bo­lo za­vád­za­jú­ce. Pra­vé re­fe­ren­cie sú pres­ne to, čo po­zná­me z Pas­ca­lu pod ter­mí­nom uka­zo­va­teľ (po­in­ter). Perl ne­de­fi­nu­je špe­ciál­ny dá­to­vý typ ur­če­ný na uc­ho­vá­va­nie re­fe­ren­cií. Re­fe­ren­cie sú jed­no­duc­hé ska­lár­ne hod­no­ty. Na tom­to mies­te je po­treb­né uviesť, že Perl im­pli­cit­ne ne­vy­ko­ná­va re­fe­ren­cie ale­bo de­re­fe­ren­cie. To zna­me­ná, že vý­stu­pom frag­men­tu (6) bu­de (7), a nie ob­sah dá­to­vej ob­las­ti, na kto­rú sa od­ka­zu­je.

(6) $foo­Da­ta = "foo­Da­ta";
    $foo­Ref  = \$foo­Da­ta; #re­fe­ren­co­va­nie
    print $foo­Ref;

(7) SCA­LAR(0xb75df4)

Ako je z vý­stu­pu zrej­mé, Perl si pa­mä­tá, na aký typ ob­jek­tu re­fe­ren­cia od­ka­zu­je (pre­fix SCA­LAR), a, sa­moz­rej­me, ad­re­su do dá­to­vej ob­las­ti prog­ra­mu. Tie­to in­for­má­cie sú uc­ho­vá­va­né v ta­buľ­ke sym­bo­lov.

Pro­ces re­fe­ren­cie
Re­fe­ren­cia je pro­ces, kto­ré­ho vý­sled­kom je zís­ka­nie re­fe­ren­cie na ma­ni­pu­lo­va­ný ob­jekt. Syn­tax je po­mer­ne jed­no­duc­há (8). Sym­bol da­ta iden­ti­fi­ku­je ob­jekt, kto­ré­ho re­fe­ren­ciu po­ža­du­je­me. Znak back slash pra­cu­je po­dob­ne ako ad­re­so­vý ope­rá­tor & ja­zy­ka C. Nie­koľ­ko prík­la­dov je uve­de­ných v (9).

(8) \da­ta
(9) \$foo
    \@fooArray
    \%foo­Hash
    \&foo­Sub

Konštruk­to­ry ano­nym­ných po­lí ska­lá­rov
Ano­nym­né po­le ska­lá­rov je re­gu­lár­ne po­le ska­lá­rov umies­tne­né v dá­to­vej ob­las­ti prog­ra­mu, kto­ré je prís­tup­né po­mo­cou zod­po­ve­da­jú­cej re­fe­ren­cie. Syn­tax je vy­jad­re­ná v (10). Frag­ment (11) de­fi­nu­je štvor­co­vé po­le a dvak­rát vy­pí­še pr­vok na in­dexe 1,0.

(10) $arrayRef = [ ..., ..., ...]
(11) $arrayRef = [ ["re­cord00", "re­cord01"], ["re­cord10", "re­cord11"] ];

     $foo = $$arrayRef[1];
     print $$foo[0];

     print ${${$arrayRef}[1]}[0];

Konštruk­to­ry ano­nym­ných aso­cia­tív­nych po­lí
Konštruk­tor ano­nym­né­ho aso­cia­tív­ne­ho po­ľa je po­dob­ný konštruk­to­rom po­ľa ska­lá­rov. Syn­tax je vy­jad­re­ná v (12).

(12) $has­hRef = { key0 => va­lue0, key1 => va­lue1 ... }

De­re­fe­ren­cia
De­re­fe­ren­cia je in­ver­zná ope­rá­cia k pro­ce­su re­fe­ren­cie, pri kto­rej sa po­mo­cou re­fe­ren­cie zís­ka hod­no­ta ob­jek­tu, na kto­rý da­ná re­fe­ren­cia od­ka­zu­je. Zá­klad­ným prin­cí­pom je po­dob­ne ako pri sym­bo­lic­kých re­fe­ren­ciách sub­sti­tú­cia iden­ti­fi­ká­to­ra plat­nou re­fe­ren­ciou na po­ža­do­va­ný ob­jekt. Frag­ment (13) vy­tvá­ra re­fe­ren­ciu $foo­Ref na ska­lár $foo. Prís­tup k da­nej pre­men­nej de­monštru­je v po­ra­dí dru­há fun­kcia print. Na mies­te iden­ti­fi­ká­to­ra mô­že byť blok vra­ca­jú­ci po­ža­do­va­nú re­fe­ren­ciu. Perl auto­ma­tic­ky roz­poz­ná­va sym­bo­lic­ké a pra­vé re­fe­ren­cie. Po­kiaľ blok vrá­ti ska­lár­nu pre­men­nú ob­sa­hu­jú­cu re­ťa­zec náz­vu po­ža­do­va­nej pre­men­nej, je re­fe­ren­cia inter­pre­to­va­ná ako sym­bo­lic­ká. V prí­pa­de pra­vej re­fe­ren­cie ako náv­ra­to­vej hod­no­ty je da­ná re­fe­ren­cia inter­pre­to­va­ná ako pra­vá (14).

(13) $foo­Ref = \$foo;
     print $foo;
     print $$foo­Ref;

(14) $foo     = "foo­Samp­le";
     $foo­Ref  = \$foo;
     $foo­Na­me = "foo";

     print ${$foo­Ref};
     print ${$foo­Na­me};

Na zjed­no­du­še­nie syn­taxe a zvý­še­nie či­ta­teľ­nos­ti zdro­jo­vé­ho kó­du je mož­né na prís­tup ku ska­lár­nym hod­no­tám po­lí po­užiť in­fixový ope­rá­tor -> (15), kto­rý med­zi in­dexmi v hra­na­tých a zlo­že­ných zá­tvor­kách nie je po­vin­ný (16).

(15) $arrayRef -> [0] -> [1]
(16) $arrayRef [0][1]

Typ re­fe­ren­cie
Fun­kcia ref je ek­vi­va­len­tom ty­peof iných ja­zy­kov a v prí­pa­de od­ov­zda­nia re­gu­lár­nej re­fe­ren­cie ako pa­ra­met­ra vrá­ti typ od­ka­zu, na kto­rý da­ná re­fe­ren­cia od­ka­zu­je, v opač­nom prí­pa­de vrá­ti ne­de­fi­no­va­nú hod­no­tu. Syn­tax vy­jad­ru­je (17), de­fi­no­va­né ty­py sú v (18).

(17) ref EXPR 
(18) REF, SCA­LAR, ARRAY, HASH, CO­DE, GLOB

Čas­té chy­by
Jed­nu z naj­čas­tej­ších chýb, kto­rej sa do­púš­ťa­jú prog­ra­má­to­ri, de­monštru­je frag­ment (19) a zod­po­ve­da­jú­ci vý­stup (20). Pô­vod­ným zá­me­rom auto­ra bo­lo vy­tvo­riť po­stup­ne dve po­lia ska­lá­rov a pris­tu­po­vať k nim po­mo­cou prís­luš­ných re­fe­ren­cií. Ako je zrej­mé z vý­stu­pu, obe re­fe­ren­cie $arrayRef0 a $arrayRef1 od­ka­zu­jú na rov­na­ké po­le (iden­ti­ta ad­ries dá­to­vé­ho pries­to­ru). Vy­svet­le­nie je po­mer­ne jed­no­duc­hé. Pr­vá de­fi­ní­cia po­ľa @array vy­tvo­ri­la v ta­buľ­ke sym­bo­lov zá­znam o ty­pe a ad­re­se svoj­ho umies­tne­nia, pri­čom zod­po­ve­da­jú­ce po­le bo­lo umies­tne­né do dá­to­vé­ho pries­to­ru prog­ra­mu. Dru­há de­fi­ní­cia po­uži­la už vy­tvo­re­ný zá­znam a umies­tni­la pr­vky no­vé­ho zoz­na­mu do rov­na­kej pa­mä­ťo­vej ob­las­ti (po­le bo­lo pre­pí­sa­né). Po­dob­ným prík­la­dom mô­že byť frag­ment (21).

(19) @array = ("re­cord0", "re­cord1");
     $arrayRef0 = \@array;

     @array = ("anot­herRe­cord0", "anot­herRe­cord1");
     $arrayRef1 = \@array;

     for (@$arrayRef0) {
        print "$_ ";
     }

     print "\n"; 

     for (@$arrayRef1) {
        print "$_ ";
     }

     print "\n$arrayRef0 $arrayRef1";

(20) anot­herRe­cord0 anot­herRe­cord1
     anot­herRe­cord0 anot­herRe­cord1
     ARRAY(0xb75e00) ARRAY(0xb75e00)

(21) fo­reach (@foo) {
        @array = foo­Sub($_);
        @fooArray[$i] = \@array;
        $i++;
     }

Rie­še­ním je vy­tvo­re­nie kó­pie da­né­ho po­ľa. Je mož­né po­užiť konštruk­tor ano­nym­né­ho po­ľa (22), prí­pad­ne pre cyk­lus (21) dek­la­ro­vať po­le @array kľú­čo­vým slo­vom my. Ná­roč­nej­ší mô­žu po­užiť syn­tak­tic­kú „hrač­ku“ (24).

(22) @newArray = [ @ol­dArray ];
(23) fo­reach (@foo) {
        my(@array) = foo­Sub($_);
        @fooArray[$i] = \@array;
        $i++;
     }
(24) @{$array[$i]} = @ad­dThi­sArray;

Med­zi ďal­šie čas­té, ale ľah­šie od­ha­li­teľ­nú chy­by pat­rí za­bud­nu­tie zna­ku back slash pri us­ku­toč­ne­ní re­fe­ren­cie. Pri po­uži­tí ta­ké­ho pri­ra­de­nia je pri­ra­de­ná pria­mo hod­no­ta ska­lá­ru, a prí­pad­ne po­čet pr­vkov po­ľa ska­lá­rov (25).

(25) $sca­larRef = $foo; #pri­ra­dí hod­no­tu $foo
     $arrayRef  = @foo; #pri­ra­dí po­čet pr­vkov po­ľa @foo, je vý­hod­nej­šie expli­cit­ne prec­hád­zať do ska­lár­ne­ho kon­textu po­mo­cou fun­kcie sca­lar

In­štan­tné re­fe­ren­cie
Pre ná­zor­nosť a ujas­ne­nie pred­lo­že­ných po­stu­pov ďa­lej uvád­za­me prík­la­dy de­monštru­jú­ce prá­cu s čas­to po­uží­va­ný­mi dá­to­vý­mi štruk­tú­ra­mi. Po­drob­ný opis náj­de­te v ma­nuá­lo­vých strán­kach Per­lu.

(26) #konštruk­cia po­ľa re­fe­ren­cií na po­lia ska­lá­rov
     #po­zor, nie je to is­té ako re­fe­ren­cia na po­le re­fe­ren­cií na po­lia ska­lá­rov prík­la­du (11)
     @fooArray = ( ["re­cord00","re­cord01"], ["re­cord10","re­cord11"] );

     #vy­tvo­re­nie dup­li­ci­ty riad­kov
     $foo = @fooArray;
     for ($i=0; $i<$foo; $i++) {
        push(@fooArray, [ @{$fooArray[$i]} ]);
     }

     #tra­verz pr­vka­mi
     for (@fooArray) {
        print "$_\n";
           for (@$_) {
              print "  $_ ";
           }
        print "\n";
     }

     #prís­tup k jed­né­mu pr­vku
     print "$fooArray[0][1]\n";
     print "$fooArray[0]->[1]\n";
     print "${$fooArray[0]}[1]\n";

(27) #konštruk­cia po­ľa re­fe­ren­cií na aso­cia­tív­ne po­lia
     @fooArray = ( {"key00" => "va­lue00", "key01" => "va­lue01"}, {"key10" => "va­lue10", "key11" => "va­lue11"});

     #vy­tvo­re­nie dup­li­ci­ty riad­kov
     $foo = @fooArray;
     for ($i=0; $i<$foo; $i++) {
        push(@fooArray, { %{$fooArray[$i]} });
     }

     #tra­verz pr­vka­mi
     fo­reach $current (@fooArray) {
        print "$current\n";
           for (keys %$current) {
              print "   key = $_, va­lue = ${$current}{$_}";
           }
        print "\n";
     }

     #prís­tup k jed­né­mu pr­vku
     print "$fooArray[0]{'key00'}\n";
     print "$fooArray[0]->{'key00'}\n";
     print "${$fooArray[0]}{'key00'}\n";

(28) #konštruk­cia aso­cia­tív­ne­ho po­ľa re­fe­ren­cií na po­lia ska­lá­rov
     %fooArray = ( "hash0" => ["re­cord00", "re­cord01"], "hash1" => ["re­cord10", "re­cord11"]);

     #vy­tvo­re­nie dup­li­ci­ty riad­kov
     @foo = keys %fooArray;
     fo­reach (@foo) {
        $foo­Hash{'A$_'} = [ @{$foo­Hash{$_}} ];
     }

     #tra­verz pr­vka­mi
     fo­reach $current (keys %fooArray) {
        print "$fooArray{$current}\n";
        for (@{$fooArray{$current}}) {
           print "   $_";
        }
        print "\n";
     }

     #prís­tup k jed­né­mu pr­vku
     print "$fooArray{hash0}[0]\n";
     print "$fooArray{hash0}->[0]\n";
     print "${$fooArray{hash0}}[0]\n";

(29) #konštruk­cia aso­cia­tív­ne­ho po­ľa re­fe­ren­cií na aso­cia­tív­ne po­lia
     %fooArray = ( "hash0" => {"key00" => "va­lue00", "key01" => "va­lue01"}, "hash1" => {"key10" => "va­lue10", "key11" => "va­lue11"});

     #vy­tvo­re­nie dup­li­ci­ty riad­kov
     @foo = keys %fooArray;
     for (@foo) {
        $fooArray{"B$_"} = { %{$fooArray{$_}} };
     }

     #tra­verz pr­vka­mi
     fo­reach $current (keys %fooArray) {
        print "$fooArray{$current}\n";
        for (keys %{$fooArray{$current}}) {
           print "   key = $_, va­lue = ${$fooArray{$current}}{$_}";
        }
        print "\n";
     }

     #prís­tup k jed­né­mu pr­vku
     print "$fooArray{hash0}{key00}\n";
     print "$fooArray{hash0}->{'key00'}\n";
     print "${$fooArray{hash0}}{'key00'}\n";

(30) #im­ple­men­tá­cia jed­no­duc­hé­ho zá­zna­mu
     %fooArray = ( "hash" => ["re­cord00", "re­cord01"], "string" => "re­cord10", "va­lue" => 320);

     fo­reach $current (keys %fooArray) {
        print "Key: $current, Va­lue: $fooArray{$current}\n";

        if (ref($fooArray{$current}) eq 'ARRAY') {
           for (@{$fooArray{$current}}) {
              print "   $_";
           }
           print "\n";
        }
        print "\n";
     }

Gar­ba­ge Collec­tor
Ter­mín Gar­ba­ge Collec­tor ozna­ču­je mec­han­izmus za­bez­pe­ču­jú­ci ko­rek­tné a správ­ne uvoľ­ňo­va­nie zdro­jov sys­té­mu. Pa­mä­ťo­vé mies­ta ob­jek­tov sú dea­lo­ko­va­né, len čo po­čet re­fe­ren­cií od­ka­zu­jú­cich sa na ne do­siah­ne nu­lu. Po­zor na cyk­lic­ké od­ka­zy, kto­ré Perl do­te­raz ne­vie iden­ti­fi­ko­vať. Ďal­šie in­for­má­cie o sys­té­me uvoľ­ňo­va­nia zdro­jov bu­dú uve­de­né v po­kra­čo­va­ní za­obe­ra­jú­com sa ob­jek­tmi Per­lu.

Po­dprog­ra­my
Nep­ri­rod­ze­ný a za­vád­za­jú­ci ter­mín po­dprog­ram vo sve­te Per­lu za­stre­šu­je po­uží­va­teľ­sky de­fi­no­va­né auto­nóm­ne blo­ky kó­du iný­mi prog­ra­mo­va­cí­mi ja­zyk­mi, všeo­bec­ne ozna­čo­va­né ako pro­ce­dú­ry a fun­kcie. Nas­le­du­jú­ci text pred­pok­la­dá oboz­ná­me­nie sa či­ta­te­ľa s prob­le­ma­ti­kou re­fe­ren­cií.

Dek­la­rá­cia a de­fi­ní­cia po­dprog­ra­mov
Perl nek­la­die strik­tné ob­med­ze­nia na umies­tne­nie po­dprog­ra­mu v prog­ra­mo­vom blo­ku. Po­dprog­ra­my mô­žu byť umies­tne­né v exter­ných sú­bo­roch ale­bo ge­ne­ro­va­né za cho­du. Zá­klad­ná dek­la­rá­cia a de­fi­ní­cia je vy­jad­re­ná (31), kde NA­ME je uni­kát­ne ozna­če­nie po­dprog­ra­mu a BLOCK blok prog­ra­mo­vej čas­ti po­dprog­ra­mu. Dek­la­rá­ciu a de­fi­ní­ciu s pro­to­ty­pom vy­jad­ru­je (32). Po­dob­ne ako mno­hé ja­zy­ky, aj Perl umož­ňu­je „dop­red­nú“ (Forward) dek­la­rá­ciu (33) a (34), kto­rá sa čas­to po­uží­va s pro­to­ty­po­vý­mi po­dprog­ra­ma­mi. De­fi­ní­cia ano­nym­né­ho po­dprog­ra­mu je vy­jad­re­ná v (35).

(31) sub NA­ME BLOCK
(32) sub NA­ME (PRO­TO) BLOCK
(33) sub NA­ME;
(34) sub NA­ME (PRO­TO);
(35) $sca­lar­Var = sub BLOCK;

Pro­to­ty­py
Dek­la­rá­cia po­dprog­ra­mov s exak­tne de­fi­no­va­nou štruk­tú­rou vstup­ných pa­ra­met­rov je mož­ná za po­mo­ci pro­to­ty­po­vých dek­la­rač­ných konštruk­cií. Po­dprog­ra­my sa sprá­va­jú ako pro­to­ty­po­vé len v prí­pa­de vo­la­nia po­mo­cou tzv. „new sty­le“ vo­la­cích konštruk­cií, za kto­ré sa po­va­žu­jú vo­la­nia bez po­uži­tia zna­ku & ako pre­fixu (po­zri sek­ciu vo­la­nie po­dprog­ra­mov). To zna­me­ná, že nep­ria­me vo­la­nia a vo­la­nia od­ka­zom bu­dú inter­pre­to­va­né ako nep­ro­to­ti­po­vé. Pro­to­typ je de­fi­no­va­ný ako sek­ven­cia zna­kov z mno­ži­ny (36). Znak $ pre­be­rá pa­ra­me­ter v ska­lár­nom kon­texte, čo de­monštru­je frag­ment (37) a zod­po­ve­da­jú­ci vý­stup (38). Po­dprog­ra­mu foo­Sub bu­de pri pr­vom vo­la­ní s po­uži­tím pre­fixu & od­ov­zda­ný ce­lý zoz­nam @fooArray. Dru­hé „new sty­le“ vo­la­nie je v po­dsta­te ek­vi­va­len­tné, pre­to­že de­fi­ní­cia pro­to­ty­pu inter­pre­te­ra eš­te nie je zná­ma, a tak bu­de po­dob­ne od­ov­zda­né ce­lé po­le @fooArray. Po­sled­né vo­la­nie vy­hod­no­tí @fooArray v ska­lár­nom kon­texte (po­čet pr­vkov) a vý­sled­nú hod­no­tu od­ov­zdá ako pa­ra­me­ter po­dprog­ra­mu foo­Sub.

 (36) $@%&*;\
 (37) @fooArray = ("re­cord0", "re­cord1");

      &foo­Sub(@fooArray);
      foo­Sub(@fooArray);

      sub foo­Sub ($) {
         for (@_) {
            print "$_ ";
         }
         print "\n";
      }

      foo­Sub(@fooArray);

 (38) re­cord0 re­cord1
      re­cord0 re­cord1
      2

Zna­ky @ a % ma­jú ten­den­ciu po­hl­tiť všet­ky nas­le­du­jú­ce pa­ra­met­re. Znak \ pred pro­to­ty­po­vým zna­kom ($, @, %, &, *) de­fi­nu­je da­ný pa­ra­me­ter ako sku­toč­ný. Sku­toč­ný pa­ra­me­ter mu­sí byť uve­de­ný s to­tož­ným pre­fixom ako k ne­mu re­le­vant­ný pro­to­ty­po­vý dvoj­ník. Po­lia ska­lá­rov a aso­cia­tív­ne po­lia sú po­dprog­ra­mu od­ov­zda­né od­ka­zom. Prík­lad po­uži­tia de­monštru­je frag­ment (39) a zod­po­ve­da­jú­ci vý­stup (40). Pr­vý pa­ra­me­ter po­dob­ne ako v prík­la­de (37) je vy­hod­no­te­ný v ska­lár­nom kon­texte. Dru­hý pa­ra­me­ter je od­ov­zda­ný ako sku­toč­ný, to zna­me­ná, že po­dprog­ram foo­Sub dos­ta­ne v po­li vstup­ných pa­ra­me­te­rov na in­dexe 1 od­kaz na po­le @fooArray (\@fooArray). Po­sled­ným pa­ra­met­rom je po­le ska­lá­rov, kto­ré po­hl­tí všet­ky ďal­šie pa­ra­met­re a umies­tni ich v rov­na­kom po­ra­dí do po­ľa vstup­ných pa­ra­met­rov.

 (39) @fooArray = ("re­cord0", "re­cord1"); $foo0 = "foo0"; $foo1 = "foo1";

     sub foo­Sub ($\@@) {
        $len = shift;      # pr­vý pa­ra­me­ter, @fooArray v ska­lár­nom kon­texte
        print "$len - ";

        $arrayRef = shift; # dru­hý pa­ra­me­ter od­ov­zda­ný ako re­fe­ren­cia po­ľa
        for (@$arrayRef) {
           print "$_ ";
        }

        print ", ";        # os­tat­né pa­ra­met­ry
        for (@_) {
           print "$_ ";
        }
     }
    
     foo­Sub(@fooArray, @fooArray, $foo0, $foo1);

(40) 2 – re­cord0 re­cord1 , foo0 foo1

Znak & pre­be­rá pa­ra­me­ter ako ano­nym­ný po­dprog­ram. V prí­pa­de, že je ano­nym­ný po­dprog­ram ako pa­ra­me­ter na pr­vom mies­te, je uvád­za­cie sub a od­de­ľo­va­cia čiar­ka ne­po­vin­ná (41). Po­sled­ný pro­to­ty­po­vý znak * pre­vád­za pa­ra­me­ter na od­kaz. Sa­moz­rej­me, je mož­né de­fi­no­vať po­vin­né pa­ra­met­re. Po­vin­né a ne­po­vin­né pa­ra­met­re sú v de­fi­ní­cii pro­to­ty­pu od­de­le­né zna­kom ;.

(41) sub foo­Sub (&) {
        &{$_[0]};
     }

     foo­Sub { print "foo"};

Vo­la­nie po­dprog­ra­mov
Po­dprog­ram je mož­né za­vo­lať pria­mo ale­bo nep­ria­mo. Syn­tax pria­mych vo­la­ní je vy­jad­re­ná v (42). Znak & je ne­po­vin­ný. Po­kiaľ je v oka­mi­hu vo­la­nia zná­ma dek­la­rá­cia, sú zá­tvor­ky zoz­na­mu pa­ra­met­rov ne­po­vin­né. Po­sled­ná syn­tax od­ov­zdá­va po­dprog­ra­mu po­le ska­lá­rov @_ ako pa­ra­me­ter. Pri nep­ria­mom (43) vo­la­ní je pre­fixový znak & po­vin­ný. Po­dob­ne po­sled­ná syn­tax od­ov­zdá­va po­dprog­ra­mu po­le ska­lá­rov @_ ako pa­ra­me­ter.

(42) &SUB­NA­ME(ARGLIST);
     &SUB­NA­ME ARGLIST;
     &SUB­NA­ME;
(43) &$SUB­NA­ME(ARGLIST)
     &$SUB­NA­ME;

Sys­tém od­ov­zdá­va­nia pa­ra­met­rov
Krá­sa a flexibil­nosť sys­té­mu od­ov­zdá­va­nia pa­ra­met­rov vy­nik­ne až pri dek­la­ro­va­ní a de­fi­no­va­ní po­dprog­ra­mov. Na pr­vý po­hľad jed­no­duc­hý mo­del Per­lu je je­den z naj­lep­ších a naj­ele­gan­tnej­ších vô­bec. Všet­ky pa­ra­met­re sú od­ov­zdá­va­né v je­di­nom po­li ska­lá­rov @_. Vý­stup je po­dob­ne oča­ká­va­ný v po­li ska­lá­rov. Po­le vstup­ných ar­gu­men­tov je lo­kál­ne, ale ob­sa­hu­je im­pli­cit­né od­ka­zy na jed­not­li­vé pa­ra­met­re. Iný­mi slo­va­mi to zna­me­ná, že mô­že­te mo­di­fi­ká­ciou pr­vkov po­ľa @_ pria­mo me­niť hod­no­ty prís­luš­ných pre­men­ných. Po­dprog­ram bez de­fi­no­va­né­ho pro­to­ty­pu mô­že­te za­vo­lať všeo­bec­ne s ľu­bo­voľ­ným po­čtom ar­gu­men­tov, pri­čom po­lia ska­lá­rov a aso­cia­tív­ne po­lia bu­dú tran­sfor­mo­va­né na mno­ži­nu ska­lá­rov a ulo­že­né v po­li @_. Po­le @_ vy­stu­pu­je ako pl­no­hod­not­né po­le a je mož­né nad ním vy­ko­ná­vať všet­ky ma­ni­pu­lač­né fun­kcie po­lí ska­lá­rov. Ako vý­stup je od­os­la­ný po­sled­ný vy­hod­no­te­ný vý­raz ale­bo vý­raz expli­cit­ne ur­če­ný prí­ka­zom re­turn, kto­rý vra­cia kon­tro­lu vo­la­jú­ce­mu.

Pr­vým prík­la­dom je frag­ment (44) dek­la­ru­jú­ci a de­fi­nu­jú­ci po­dprog­ram, kto­rý vy­ko­ná­va jed­no­duc­hú tran­sfor­má­ciu na vstup­ných ar­gu­men­toch a vra­cia v zá­vis­los­ti od kon­textu vo­la­nia po­le da­ných pr­vkov, prí­pad­ne ich pr­vý pr­vok. Pr­vé vo­la­nie po­dprog­ra­mu je v kon­texte zoz­na­mu s dvo­ma li­te­rár­mi a jed­ným po­lom ska­lá­rov ako pa­ra­met­ra­mi. Dru­hé vo­la­nie expli­cit­ne vy­nu­cu­je ska­lár­ny kon­text. V čas­ti de­fi­nu­jú­cej sa­mot­ný po­dprog­ram vás pred­pok­la­dám, za­uja­lo zdan­li­vo zby­toč­né vy­tvo­re­nie kó­pie po­ľa @_. Vy­tvo­re­nie kó­pie je ne­vyh­nut­né, po­kiaľ chce­me po­vo­liť mož­nosť od­ov­zda­nia li­te­rá­rov ako vstup­ných pa­ra­met­rov. Dru­hým za­ují­ma­vým mies­tom je po­dmien­ka na kon­ci de­fi­ní­cie, kto­rá v zá­vis­los­ti od kon­textu, v kto­rom bol po­dprog­ram vo­la­ný, vrá­ti ce­lé po­le ale­bo iba je­ho pr­vý pr­vok. Fun­kcia wan­tarray vra­cia prav­du, po­kiaľ bol po­dprog­ram vo­la­ný v kon­texte zoz­na­mu.

(44) sub foo­Sub {
        @arg = @_;
        for (@arg) {
           tr/a-z/A-Z/
        }

        re­turn wan­tarray ? @arg : @arg[0];
     }

     @foo = ("foo0", "foo1");

     for (&foo­Sub("anot­her­Foo0", "anot­her­Foo1", @foo)) {
        print "$_\n"
     }

     print sca­lar(&foo­Sub("anot­her­Foo0", "anot­her­Foo1", @foo));

Ako sme už spo­me­nu­li, je mož­né pria­mo ope­ro­vať nad po­ľom @_, po­kiaľ vy­pus­tí­me po­dmien­ku ko­rek­tnos­ti sprá­va­nia sa po­dprog­ra­mu pre pra­vé li­te­rá­ry, bu­de vý­sled­ný po­dprog­ram vy­ze­rať nas­le­dov­ne:

(45) sub foo­Sub {
        for (@_) {
           tr/a-z/A-Z/
        }

        re­turn wan­tarray ? @_ : @_[0];
     }

     @foo = ("foo0", "foo1");

     ($foo0, $foo1) = &foo­Sub(@foo);

     print "$foo0 $foo1 ";
     print sca­lar(&foo­Sub(@foo));

Ve­nuj­te po­zor­nosť konštruk­cii pri­ra­de­nia v prí­pa­de pr­vé­ho vo­la­nia po­dprog­ra­mu. Po­dprog­ram je vo­la­ný v kon­texte zoz­na­mu, kto­rý je pri­ra­de­ný ska­lár­nym pre­men­ným $foo0 a $foo1. Po­dob­né konštruk­cie sú po­uží­va­né pri “de­kó­do­va­ní” pa­ra­met­rov po­ľa @_. Čas­tým skla­ma­ním za­čí­na­jú­cich prog­ra­má­to­rov je zdan­li­vo ne­ko­rek­tné sprá­va­nie konštruk­čne po­dob­né­ho pri­ra­de­nia (46), kto­ré napl­ní po­le @foo0 vý­stu­pom po­dprog­ra­mu foo­Sub ek­vi­va­len­tne ako pri­ra­de­nie (47).

(46) (@foo0, @foo1) = &foo­Sub(@foo2, @foo3)
(47) @foo0 = &foo­Sub(@foo2, @foo3)

Je to pre­to, le­bo, ako sme už uvied­li, po­dprog­ram vra­cia po­le ska­lá­rov. Rie­še­ním je po­uži­tie od­ka­zov ale­bo ty­peg­lo­bov. Ďal­šou mož­nos­ťou je nep­ria­me vo­la­nie po­dprog­ra­mu od­ka­zom ale­bo náz­vom (48).

(48) sub foo­Sub {
	print "foo\n";
     }

     $foo0 = \&foo­Sub;
     $foo1 = "foo­Sub";

     &$foo0;
     &$foo1;

Po­dprog­ra­my a re­fe­ren­cie
Čas­to od­ov­zdá­va­ný­mi pa­ra­met­ra­mi po­dprog­ra­mov sú re­fe­ren­cie ob­jek­tov (49), po­mo­cou kto­rých je mož­né po­dprog­ra­mu od­ov­zdať po­lia ska­lá­rov ale­bo aso­cia­tív­ne po­lia bez stra­ty ich iden­ti­ty (de­ge­ne­rá­cia do @_).

(49) (\@fooArray0, \@fooArray1) = foo­Sub(\@fooArray2, \@fooArray3);

Po­dprog­ra­my a ty­peg­lo­by
Ty­peg­lob bol do­ne­dáv­na je­di­ným pros­tried­kom umož­ňu­jú­cim od­ov­zdať po­dprog­ra­mu ne­de­ge­ne­ro­va­né po­lia. Ter­mín ty­peg­lob ná­zor­ne ob­jas­ňu­je frag­ment (50). Ty­peg­lob je de­fi­no­va­ný ako od­kaz na všet­ky ob­jek­ty s da­ným náz­vom. V po­ra­dí štvr­tým pri­ra­de­ním frag­men­tu (50) je vy­tvo­re­nie alia­su všet­kým ob­jek­tom s iden­ti­fi­ká­to­rom to­tož­ným s re­ťaz­com „foo“. Iný­mi slo­va­mi, re­fe­ren­cia @foo uka­zu­je do rov­na­kej dá­to­vej ob­las­ti ako @anot­her­Foo atď. Dô­ka­zom je po­sled­ná časť, vy­tvá­ra­jú­ca a vy­pi­su­jú­ca re­fe­ren­cie na štan­dard­ný vý­stup.

(50) #de­fi­ní­cia ska­lá­ra $foo, po­ľa ska­lá­rov @foo a aso­cia­tív­ne­ho po­ľa %foo
     $foo = "fooS­ca­lar";
     @foo = ( "foo­Re­cord0", "foo­Re­cord1");
     %foo = ( "foo­Key0" => "foo­Key1");

     #vy­tvo­re­nie alia­su
     *anot­her­Foo = *foo;

     #po­rov­na­nie re­fe­ren­cií
     $foo­Ref        = \@foo;
     $anot­her­Foo­Ref = \@anot­her­Foo;

     print "$foo­Ref $anot­her­Foo­Ref";

Nie­ke­dy je vý­hod­né vy­tvo­riť alias len jed­né­ho kon­krét­ne­ho ob­jek­tu. Na tom slú­ži pri­ra­de­nie (51), vy­tvá­ra­jú­ce alias na aso­cia­tív­ne po­le %foo. Prá­ve pri­ra­de­nie (51) sa čas­to po­uží­va pri od­ov­zdá­va­ní pa­ra­met­rov po­dprog­ra­mom (52). Tre­ba si uve­do­miť ob­med­ze­nie na ob­jek­ty ba­lí­ka.

(51) #re­fe­ren­cie \%anot­her­Foo a \%foo sú to­tož­né
     *anot­her­Foo = *foo;
(52) sub foo­Sub {
        *foo = shift;
        re­turn \@foo;
     }
     
     *anot­her­Foo = sub(\@foo);

Sum­ma sum­ma­rum
Re­fe­renč­ný mo­del je pre prog­ra­má­to­rov jed­nou z kri­tic­kých ka­pi­tol Per­lu, kto­rej zna­losť je po­treb­ná na po­ro­zu­me­nie nes­kor­šie­ho vý­kla­du. Nap­riek svoj­mu na pr­vý po­hľad kom­pli­ko­va­né­mu a v mno­hých sme­roch kon­cep­čne ne­poc­ho­pi­teľ­né­mu cha­rak­te­ru je re­fe­renč­ný mo­del Per­lu v mno­hých sme­roch flexibil­nej­ší než im­ple­men­tá­cie iných ja­zy­kov.

Kam by ste sa ma­li po­zrieť
http://www.perl.org

Zdroj: PC Revue 3/1998



Ohodnoťte článok:
   
 

24 hodín

týždeň

mesiac

Najnovšie články

Svet Per­lu: 3. časť / Re­fe­ren­cie a po­dprog­ra­my
Jedným zo závažných nedostatkov Perlu bola donedávna absencia podpory komplexných dátových štruktúr podobných pascalovským záznamom alebo štruktúram jazyka C. čítať »
 
Svet Per­lu: 2. časť / Re­gu­lár­ne vý­ra­zy
Ako sme už v prvej časti seriálu načrtli, majoritná časť skriptov Perlu je vyvíjaná pre potreby spracovania textových informácií, pre ktoré Perl implementuje čítať »
 
Svet Per­lu: 1. časť / Za­čí­na­me
Perl (Practical Extraction and Reporting Language) vytvoril v roku 1986 systémový programátor Larry Wall pre potreby riadenia a správy konfigurácie systémov Unix. čítať »
 
 
 
  Zdieľaj cez Facebook Zdieľaj cez Google+ Zdieľaj cez Twitter Zdieľaj cez LinkedIn Správy z RSS Správy na smartfóne Správy cez newsletter