Perl - sub-rotinas

Uma sub-rotina ou função Perl é um grupo de instruções que, juntas, executam uma tarefa. Você pode dividir seu código em sub-rotinas separadas. Como você divide seu código entre diferentes sub-rotinas é com você, mas logicamente a divisão geralmente é para que cada função execute uma tarefa específica.

Perl usa os termos sub-rotina, método e função alternadamente.

Definir e chamar uma sub-rotina

A forma geral de definição de uma sub-rotina na linguagem de programação Perl é a seguinte -

sub subroutine_name {
   body of the subroutine
}

A maneira típica de chamar essa sub-rotina Perl é a seguinte -

subroutine_name( list of arguments );

Nas versões do Perl anteriores à 5.0, a sintaxe para chamar sub-rotinas era ligeiramente diferente, conforme mostrado abaixo. Isso ainda funciona nas versões mais recentes do Perl, mas não é recomendado, pois ignora os protótipos da sub-rotina.

&subroutine_name( list of arguments );

Vamos dar uma olhada no exemplo a seguir, que define uma função simples e depois a chama. Como o Perl compila seu programa antes de executá-lo, não importa onde você declara sua sub-rotina.

#!/usr/bin/perl

# Function definition
sub Hello {
   print "Hello, World!\n";
}

# Function call
Hello();

Quando o programa acima é executado, ele produz o seguinte resultado -

Hello, World!

Passando Argumentos para uma Sub-rotina

Você pode passar vários argumentos para uma sub-rotina como você faz em qualquer outra linguagem de programação e eles podem ser acessados ​​dentro da função usando o array especial @_. Portanto, o primeiro argumento para a função está em $ _ [0], o segundo está em $ _ [1] e assim por diante.

Você pode passar arrays e hashes como argumentos como qualquer escalar, mas passar mais de um array ou hash normalmente faz com que percam suas identidades separadas. Portanto, usaremos referências (explicadas no próximo capítulo) para passar qualquer array ou hash.

Vamos tentar o exemplo a seguir, que pega uma lista de números e imprime sua média -

#!/usr/bin/perl

# Function definition
sub Average {
   # get total number of arguments passed.
   $n = scalar(@_);
   $sum = 0;

   foreach $item (@_) {
      $sum += $item;
   }
   $average = $sum / $n;

   print "Average for the given numbers : $average\n";
}

# Function call
Average(10, 20, 30);

Quando o programa acima é executado, ele produz o seguinte resultado -

Average for the given numbers : 20

Passando listas para sub-rotinas

Como a variável @_ é uma matriz, ela pode ser usada para fornecer listas a uma sub-rotina. No entanto, devido à maneira como o Perl aceita e analisa listas e arrays, pode ser difícil extrair os elementos individuais de @_. Se você tiver que passar uma lista junto com outros argumentos escalares, faça lista como o último argumento como mostrado abaixo -

#!/usr/bin/perl

# Function definition
sub PrintList {
   my @list = @_;
   print "Given list is @list\n";
}
$a = 10;
@b = (1, 2, 3, 4);

# Function call with list parameter
PrintList($a, @b);

Quando o programa acima é executado, ele produz o seguinte resultado -

Given list is 10 1 2 3 4

Passando Hashes para Sub-rotinas

Quando você fornece um hash para uma sub-rotina ou operador que aceita uma lista, o hash é automaticamente traduzido em uma lista de pares de chave / valor. Por exemplo -

#!/usr/bin/perl

# Function definition
sub PrintHash {
   my (%hash) = @_;

   foreach my $key ( keys %hash ) {
      my $value = $hash{$key};
      print "$key : $value\n";
   }
}
%hash = ('name' => 'Tom', 'age' => 19);

# Function call with hash parameter
PrintHash(%hash);

Quando o programa acima é executado, ele produz o seguinte resultado -

name : Tom
age : 19

Retornando valor de uma sub-rotina

Você pode retornar um valor da sub-rotina como faria em qualquer outra linguagem de programação. Se você não estiver retornando um valor de uma sub-rotina, qualquer cálculo executado pela última vez em uma sub-rotina também será automaticamente o valor de retorno.

Você pode retornar matrizes e hashes da sub-rotina como qualquer escalar, mas retornar mais de uma matriz ou hash normalmente faz com que percam suas identidades separadas. Portanto, usaremos referências (explicadas no próximo capítulo) para retornar qualquer array ou hash de uma função.

Vamos tentar o exemplo a seguir, que pega uma lista de números e retorna sua média -

#!/usr/bin/perl

# Function definition
sub Average {
   # get total number of arguments passed.
   $n = scalar(@_);
   $sum = 0;

   foreach $item (@_) {
      $sum += $item;
   }
   $average = $sum / $n;

   return $average;
}

# Function call
$num = Average(10, 20, 30);
print "Average for the given numbers : $num\n";

Quando o programa acima é executado, ele produz o seguinte resultado -

Average for the given numbers : 20

Variáveis ​​privadas em uma sub-rotina

Por padrão, todas as variáveis ​​em Perl são variáveis ​​globais, o que significa que podem ser acessadas de qualquer lugar no programa. Mas você pode criarprivate variáveis ​​chamadas lexical variables a qualquer momento com o my operador.

o myoperador confina uma variável a uma região específica do código na qual ela pode ser usada e acessada. Fora dessa região, esta variável não pode ser usada ou acessada. Esta região é chamada de escopo. Um escopo léxico é geralmente um bloco de código com um conjunto de colchetes ao seu redor, como aqueles que definem o corpo da sub-rotina ou aqueles que marcam os blocos de código de instruções if, while, for, foreach e eval .

A seguir está um exemplo que mostra como definir uma única ou várias variáveis ​​privadas usando my operador -

sub somefunc {
   my $variable; # $variable is invisible outside somefunc()
   my ($another, @an_array, %a_hash); # declaring many variables at once
}

Vamos verificar o exemplo a seguir para distinguir entre variáveis ​​globais e privadas -

#!/usr/bin/perl

# Global variable
$string = "Hello, World!";

# Function definition
sub PrintHello {
   # Private variable for PrintHello function
   my $string;
   $string = "Hello, Perl!";
   print "Inside the function $string\n";
}
# Function call
PrintHello();
print "Outside the function $string\n";

Quando o programa acima é executado, ele produz o seguinte resultado -

Inside the function Hello, Perl!
Outside the function Hello, World!

Valores temporários via local ()

o localé usado principalmente quando o valor atual de uma variável deve ser visível para as sub-rotinas chamadas. Um local apenas fornece valores temporários para variáveis ​​globais (significando pacote). Isso é conhecido como escopo dinâmico . O escopo lexical é feito com my, que funciona mais como as declarações automáticas de C.

Se mais de uma variável ou expressão for atribuída a local, elas devem ser colocadas entre parênteses. Este operador funciona salvando os valores atuais dessas variáveis ​​em sua lista de argumentos em uma pilha oculta e restaurando-os ao sair do bloco, sub-rotina ou eval.

Vamos verificar o exemplo a seguir para distinguir entre variáveis ​​globais e locais -

#!/usr/bin/perl

# Global variable
$string = "Hello, World!";

sub PrintHello {
   # Private variable for PrintHello function
   local $string;
   $string = "Hello, Perl!";
   PrintMe();
   print "Inside the function PrintHello $string\n";
}
sub PrintMe {
   print "Inside the function PrintMe $string\n";
}

# Function call
PrintHello();
print "Outside the function $string\n";

Quando o programa acima é executado, ele produz o seguinte resultado -

Inside the function PrintMe Hello, Perl!
Inside the function PrintHello Hello, Perl!
Outside the function Hello, World!

Variáveis ​​de estado via estado ()

Há outro tipo de variáveis ​​lexicais, que são semelhantes às variáveis ​​privadas, mas mantêm seu estado e não são reinicializadas após várias chamadas das sub-rotinas. Essas variáveis ​​são definidas usando ostate operador e disponível a partir de Perl 5.9.4.

Vamos verificar o exemplo a seguir para demonstrar o uso de state variáveis ​​-

#!/usr/bin/perl

use feature 'state';

sub PrintCount {
   state $count = 0; # initial value

   print "Value of counter is $count\n";
   $count++;
}

for (1..5) {
   PrintCount();
}

Quando o programa acima é executado, ele produz o seguinte resultado -

Value of counter is 0
Value of counter is 1
Value of counter is 2
Value of counter is 3
Value of counter is 4

Antes do Perl 5.10, você teria que escrever assim -

#!/usr/bin/perl

{
   my $count = 0; # initial value

   sub PrintCount {
      print "Value of counter is $count\n";
      $count++;
   }
}

for (1..5) {
   PrintCount();
}

Contexto de chamada de subrotina

O contexto de uma sub-rotina ou instrução é definido como o tipo de valor de retorno esperado. Isso permite que você use uma única função que retorna valores diferentes com base no que o usuário espera receber. Por exemplo, o seguinte localtime () retorna uma string quando é chamado no contexto escalar, mas retorna uma lista quando é chamado no contexto da lista.

my $datestring = localtime( time );

Neste exemplo, o valor de $ timestr agora é uma string composta pela data e hora atuais, por exemplo, Thu Nov 30 15:21:33 2000. Inversamente -

($sec,$min,$hour,$mday,$mon, $year,$wday,$yday,$isdst) = localtime(time);

Agora as variáveis ​​individuais contêm os valores correspondentes retornados pela sub-rotina localtime ().