Perl Language
Podprogramy
Szukaj…
Uwagi
Podprogramy otrzymują argumenty do zmiennej magicznej o nazwie @_
. Chociaż nie musi być rozpakowywany, jest zalecany, ponieważ poprawia czytelność i zapobiega przypadkowym zmianom, ponieważ argumenty @_
są przekazywane przez odwołanie (można je modyfikować).
Tworzenie podprogramów
Podprogramy są tworzone przy użyciu słowa kluczowego sub
po którym następuje identyfikator i blok kodu ujęte w nawiasy klamrowe.
Dostęp do argumentów można uzyskać za pomocą specjalnej zmiennej @_
, która zawiera wszystkie argumenty jako tablicę.
sub function_name {
my ($arg1, $arg2, @more_args) = @_;
# ...
}
Ponieważ funkcja shift
domyślnie shift
na przesunięcie @_
gdy jest używana wewnątrz podprogramu, powszechnym wzorem jest sekwencyjne wyodrębnianie argumentów do zmiennych lokalnych na początku podprogramu:
sub function_name {
my $arg1 = shift;
my $arg2 = shift;
my @more_args = @_;
# ...
}
# emulate named parameters (instead of positional)
sub function_name {
my %args = (arg1 => 'default', @_);
my $arg1 = delete $args{arg1};
my $arg2 = delete $args{arg2};
# ...
}
sub {
my $arg1 = shift;
# ...
}->($arg);
Alternatywnie, funkcja eksperymentalna "signatures"
może być używana do rozpakowywania parametrów, które są przekazywane przez wartość (a nie przez odniesienie).
use feature "signatures";
sub function_name($arg1, $arg2, @more_args) {
# ...
}
Dla parametrów można użyć wartości domyślnych.
use feature "signatures";
sub function_name($arg1=1, $arg2=2) {
# ...
}
Możesz użyć dowolnego wyrażenia, aby nadać parametrowi wartość domyślną - w tym inne parametry.
sub function_name($arg1=1, $arg2=$arg1+1) {
# ...
}
Zauważ, że nie możesz odwoływać się do parametrów, które są zdefiniowane po bieżącym parametrze - dlatego poniższy kod nie działa tak, jak się spodziewano.
sub function_name($arg1=$arg2, $arg2=1) {
print $arg1; # => <nothing>
print $arg2; # => 1
}
Argumenty podprogramu są przekazywane przez odwołanie (oprócz tych w podpisach)
Argumenty podprogramów w Perlu są przekazywane przez odwołanie, chyba że znajdują się w podpisie. Oznacza to, że elementy tablicy @_
w sub są tylko aliasami do rzeczywistych argumentów. W poniższym przykładzie $text
w programie głównym pozostało zmodyfikowane po wywołaniu podprogramu, ponieważ $_[0]
wewnątrz sub jest właściwie inną nazwą dla tej samej zmiennej. Drugie wywołanie powoduje błąd, ponieważ literał łańcuchowy nie jest zmienną i dlatego nie można go modyfikować.
use feature 'say';
sub edit {
$_[0] =~ s/world/sub/;
}
my $text = "Hello, world!";
edit($text);
say $text; # Hello, sub!
edit("Hello, world!"); # Error: Modification of a read-only value attempted
Aby uniknąć zapychania zmiennych wywołujących, ważne jest, aby skopiować @_
do zmiennych o @_
lokalnym ( my ...
), jak opisano w „Tworzenie podprogramów”.
Podprogramy
Podprogramy zawierają kod. O ile nie określono inaczej, są one zdefiniowane globalnie.
# Functions do not (have to) specify their argument list
sub returns_one {
# Functions return the value of the last expression by default
# The return keyword here is unnecessary, but helps readability.
return 1;
}
# Its arguments are available in @_, however
sub sum {
my $ret = 0;
for my $value (@_) {
$ret += $value
}
return $ret;
}
# Perl makes an effort to make parens around argument list optional
say sum 1..3; # 6
# If you treat functions as variables, the & sigil is mandatory.
say defined ∑ # 1
Niektóre wbudowane funkcje, takie jak print
lub say
są słowami kluczowymi, a nie funkcjami, więc np. &say
jest niezdefiniowany. Oznacza to również, że możesz je zdefiniować, ale będziesz musiał podać nazwę pakietu, aby je wywołać
# This defines the function under the default package, 'main'
sub say {
# This is instead the say keyword
say "I say, @_";
}
# ...so you can call it like this:
main::say('wow'); # I say, wow.
Od Perla 5.18 możesz także mieć funkcje nieglobalne:
use feature 'lexical_subs';
my $value;
{
# Nasty code ahead
my sub prod {
my $ret = 1;
$ret *= $_ for @_;
$ret;
}
$value = prod 1..6; # 720
say defined ∏ # 1
}
say defined ∏ # 0
Od wersji 5.20 możesz także nazywać parametry.
use feature 'signatures';
sub greet($name) {
say "Hello, $name";
}
Nie należy tego mylić z prototypami, narzędzie, które Perl musi umożliwiać definiowanie funkcji, które zachowują się jak wbudowane. Prototypy funkcji muszą być widoczne w czasie kompilacji, a ich efekty można zignorować, podając &
sigil. Prototypy są ogólnie uważane za zaawansowaną funkcję, którą najlepiej stosować z dużą ostrożnością.
# This prototype makes it a compilation error to call this function with anything
# that isn't an array. Additionally, arrays are automatically turned into arrayrefs
sub receives_arrayrefs(\@\@) {
my $x = shift;
my $y = shift;
}
my @a = (1..3);
my @b = (1..4);
receives_arrayrefs(@a, @b); # okay, $x = \@a, $y = \@b, @_ = ();
receives_arrayrefs(\@a, \@b); # compilation error, "Type … must be array …"
BEGIN { receives_arrayrefs(\@a, \@b); }
# Specify the sigil to ignore the prototypes.
&receives_arrayrefs(\@a, \@b); # okay, $x = \@a, $y = \@b, @_ = ();
&receives_arrayrefs(@a, @b); # ok, but $x = 1, $y = 2, @_ = (3,1,2,3,4);