Paprogramės, funkcijos, parametrų perdavimas

 

PERL'e sąvokos paprogramė ir funkcija - sinonimai, todėl galima vartoti tiek vieną tiek ir kitą terminą. Paprogramės paskirtis yra tokia pat kaip ir funkcijos C/C++  tai yra: suskaldyti didelę programą į mažesnes dalis tam,  kad ji būtų lengviau suprantama bei sudarytų galimybę ateityje panaudoti tą pačią paprogramę panašioms procedūroms atlikti.

Paprogramė gali būti apibrėžta bet kurioje pagrindinės programos vietoje. Paprogramei apibrėžti naudojama sintaksė:

sub vardas                        -  paprogramės sukūrimas be apibrėžimo
   sub vardas (prototipas)           -  paprogramės sukūrimas, nurodant parametrų sąrašą, bet be apibrėžimo
   sub vardas {blokas}	                         -     paprogramės apibrėžimas su operatorių bloku
   sub vardas (prototipas) {blokas}  -  paprogramės apibrėžimas su parametrų sarašu ir operatorių bloku.

Pavyzdys:

sub say_hello {
   print "hello, world!\n";
}

Paprogramėje apibrėžti ir naudojami kintamieji yra grobalūs, jei jie neapibrėžiami funkcijų  my() arba local() pagalba. Paprogramės tekstas gali būti saugomas kitame faile nei pati programa. Tuomet paprogramė prijungiama naudojant operatorius do, require, use. Funkcijos eval() argumentas gali būti paprogramė, todėl tai dar vienas būdas perduoti paprogramę pagrindinei programai.
Konstrukcija do filename siejama su specialiais kintamaisiais $! ir $@. Pirmasis naudojamas pranešimams apie sistemines klaidas saugoti, antrasis kintamasis saugo pranešimus apie paprogramės kompiliavimo arba vykdymo klaidas. Pavyzdžiui:

# Failas "1.pl"
# !/usr/bin/perl
do "2.pl";
   print " Klaida: $@\n" if $@;
   print " Sistemnine klaidas: $!\n" if $!;

# Failas "2.pl"
# !/usr/bin/perl
   $x = <>;
   $y = <>;
   print "Dalyba = ", $x/$y, "\n";

 

Paprogramės iškvietimas

Paprastai paprogramė atpažįstama pagal prefiksą &, todėl iškviečiant paprogramę galima naudoti tokia sintaksę:

    &vardas args;
    &vardas (args);
    &vardas;

Jei iškviečiant paprogramę, po jos vardo naudojami skliaustai ( ) arba prieš tai paprogramė buvo apibrėžta ar importuota, tuomet galime praleisti prefiksą "&". Jeigu paprogramė iškviečiama per nuorodą, tuomet prefiksas "&" būtinas, pavyzdžiui.

$sub_ref = sub { ..... };
...
&sub_ref (args);
...
&sub_ref;

Paprogramė gali būti naudojama kaip funkcija, grąžinanti reikšmę. Pagal nutylėjimą gražinama reikšmė, gauta iš paskutinio paprogramės skaičiavimo arba tai, kas nurodoma funkcijos return() argumente. Argumentų sąrašas, perduodamas paprogramės išvietimo metu yra saugoma specialiame masyve @_ , kuris yra lokalus ir pasiekiamas tik konkrečios paprogramės. Pavyzdys:

sub sudetis {
    $sum = 0;          
    foreach $_ (@_) {
        $sum += $_;     # sudedami visi elementai
    }
return  $sum;          
}
$a = add(4,5,6);        # sudeda 4+5+6 = 15 ir priskiria $a
print add(1,2,3,4,5);   # atspausdina 15
print add(1..5);        # taip pat 15


 

Lokalūs kintamieji paprogramėse

PERL kalboje kintamieji pagal nutylėjimą laikomi globaliais t.y. jų galiojimo sritis apribojama paketu. Paketui paprastai priklauso visa programa. Kiekvienas paketas turi savo vardų sritį (angl. namespace). Norint apriboti kintamųjų veikimo sritį bloko arba paprogramės rėmuose, naudojami lokalūs kintamieji. Jie papibrėžiami funkcijomis my() ir local().


Funkcija my()

Ši funkcija apibrėžia lokalų  kintamąjį. Sintaksė:

    my (Expr_list);
    my Expr;

Pavyzdys:

sub add {
    my ($sum)= 0;          # $sum lokalus kintamasis
    foreach $_ (@_) {
        $sum += $_;        # sumuojam visus elementus
    }
    return $sum;           
}

Lokalūs kintamieji, apibrėžti funkcija my(), veikimo sritis:


Funkcija local()

Ši funkcija apibrėžia kintamąjį, bet ne lokalų, o laikinas reikšmes globaliems kintamiesiems:

Sintaksės variantai:

      local Expr;
 
 local ($myvar, @myarray, %myhash);

   local $pi = 3.1415;
   local ($pi, @array) = (3.1514, 1, 2);


Svarbu suprasti skirtumus tarp funkcij
ų my() ir local(). Tai padės pavydžiai:

$value = "Originalus";
  output();
  keisti();
  output();
sub keisti {
    local ($value) = "Laikinas";    # Naudojam funkciją local
    output();
} 
sub output {
    print "$value\n";
} 

Rezultatai bus tokie:

 Originalus
 Laikinas
 Originalus

Jei pakeisime paprogramėje keisti() funkciją local į my(), tuomet rezultatai bus tokie:

 Originalus
 
Originalus
 Originalus


 

Parametrų perdavimas paprogramėms

Informacija paprogramei ir atgal perduodama per parametrus (argumentus). Parametrų perdavimas paprogramei atliekamas per specialų kintamąjį @_ , kuris yra lokalus duotai paprogramei.  Visi parametrai saugomi masyvo elementuose $_[0], $_[1] ... Toks mechanizmas leidžia perduoti neapibrėžtą parametrų skaičių. Parametrų perdavimas per kintamąjį  @_ prilygsta C/C++ naudojamai nuorodos paskirčiai funkcijos parametrų sąraše.

Jei paprogramės parametras yra masyvas, jo elementai taip pat prisikiriami masyvo @_ elementams. Tačiau, jei norima perduoti ne vieną, o kelis masyvus, tuomet naudojami typeglob tipo kintamieji arba nuorodos. typeglob tipo kintamieji turi prefiksą "*", kuris reiškia, kad dirbama su kintamųjų vardų sritimi ir kintamasis sutokiu pavadinimu gali būti bet kokio tipo t. y. skaliarinis, masyvas, asociatyvinis masyvas ar funkcija. Kitaip sakant, "*" reiškia nuorodą į simbolių lentelę. Naudojant paprogramės parametrų sąraše typeglob kintamuosius, imituojamas duomenų perdavimas per nuorodas, pavyzdžiui:

# Duomenų perdavimas paprogramėms per typeglob kintamuosius

sub double_arg {
    local (*mylist, *myhash) = @_;         # būtina naudoti local()
    foreach $item (@mylist) {
    $item *=2;
    }
foreach $key (keys %myhash) {
    $myhash{$key} *=2;
    }
}
@somelist = (1,2,3);
%somehash = ("one"=>5, "two"=>6, "three"=>7);
  print "Pradines reiksmes:\n\@somelist = @somelist\n";
  foreach $key (keys %somehash) {
     print "\$somehash{$key} = $somehash{$key}";
}
double_arg(*somelist, *somehash);
  print "Pakeistos reiksmes:\n\@somelist = @somelist\n";
  foreach $key (keys %somehash) {
     print "\$somehash{$key} = $somehash{$key}";
}

Kitas būdas  keletos masyvus perdavimui paprogramei  - tai  nuorodų panaudojimas. Nuorodos PERL'e yra skaliariniai kintamieji, todėl jie perduodami, per specialų kintamąjį @_ kaip ir bet kuris kitas skaliaras. Ankstesnis pavyzdys, panaudojus nuorodas, atrodytų taip:

# Duomenų perdavimas paprogramėms per nuorodas
sub double_arg {
    my($listref, $hashref) = @_;            # būtina naudoti my()
    foreach $item (@$listref) {
    $item *=2;
    }
foreach $key (keys %$hashref) {
    $$hashref{$key} *=2;
    }
}
@somelist = (1,2,3);
%somehash = ("one"=>5, "two"=>6, "three"=>7);
  print "Pradines reiksmes:\n\@somelist = @somelist\n";
  foreach $key (keys %somehash) {
     print "\$somehash{$key} = $somehash{$key}";
}
double_arg(\@somelist, \%somehash);
  print "Pakeistos reiksmes:\n\@somelist = @somelist\n";
  foreach $key (keys %somehash) {
     print "\$somehash{$key} = $somehash{$key}";
}

Nuorodos taip pat naudojamos ir tuo atveju, kai norima iš paprogramės grąžinti daugiau nei vieną masyvą, pavydžiui:

($array_ref, $hash_ref) = somefunc();

sub somefunc {
    my @array;
    my %hash;

    # ...

    return ( \@array, \%hash );
}


 

Prototipai

Visos PERL built-in funkcijos turi apibrėžtą sintaksę, t.y. vardą, parametrų skaičių ir jų tipą. Norint apibrėžti, kokio tipo parametrai turi būti įvedami iškviečiant funkciją, naudojami prototipai. Prototipas - tai įrašas funkcijos parametrų sąrašę, kuris tam tikrais simboliais apibrėžia, kiek ir kokie parametrai turi būti įvedami. Prototipe naudojami sekantys simboliai:

Simbolis Duomenų tipas
$  Skaliarinis
@  Masyvas
%  Asociatyvinis masyvas
&  Anoniminė paprogramė
*  typeglob
;  Skiria būtinus parametrus nuo nebūtinų
\  Pasako, kad parametro vardas, turi prasidėti simbolių, einančiu po \

 

Prototipų pavyzdžiai

Apibrėžtas prototipas Funkcijos iškvietimas
sub mylink ($$) mylink $old, $new
sub myvec ($$$) myvec $var, $offset, 1
sub myindex ($$;$) myindex &getstring, "substr"
sub mysyswrite ($$$;$) mysyswrite $buf, 0, length($buf) - $off, $off
sub myreverse (@) myreverse $a,$b,$c
sub myjoin ($@) myjoin ":",$a,$b,$c
sub mypop (\@) mypop @array
sub mysplice (\@$$@) mysplice @array,@array,0,@pushme
sub mykeys (\%) mykeys %{$hashref}
sub myopen (*;$) myopen HANDLE, $name
sub mypipe (**) mypipe READHANDLE, WRITEHANDLE
sub mygrep (&@) mygrep { /foo/ } $a,$b,$c
sub myrand ($) myrand 42
sub mytime () mytime

 


 

Rekursinės paprogramės

PERL programose galima naudoti rekursines paprogrames. Rekursinių paprogramių kintamieji turi būti lokalūs t.y. apibrėžti funkcijomis my() arba local(). Todėl kiekvieną kartą, kai paprogramė iškviečia pati save, sukuriama nauja kintamųjų kopija. Panagrinėkime pavyzdį, kuris parodo katalogo ir jame esančių subkatalogų failų sąrašus.

sub tree {
  local (*ROOT);
  my ($root) = $_[0];
  opendir ROOT, $root;
  my (@filelist) = readdir ROOT;
  closedir ROOT;
  for $x (@filelist) {
     if ($x ne "." and $x ne "..") {
         $x = $root."/".$x;
         print " $x\n" if (-f $x);
         if (-d $x) {
            print "$x:\n";
            system (sleep 1);
            tree($x);
         }
     }
  }
}

 

Į turinį