Ορίσματα και @_#
Όταν μια sub καλείται με τον κλασικό τρόπο (χωρίς υπογραφή), η Perl ισοπεδώνει ολόκληρη τη λίστα ορισμάτων σε έναν ενιαίο πίνακα και τον εκθέτει μέσα στο σώμα ως @_. Τα στοιχεία αυτού του πίνακα δεν είναι αντίγραφα - είναι ψευδώνυμα προς τις εκφράσεις του καλούντος. Αυτός ο ενιαίος κανόνας είναι η πηγή των περισσότερων εκπλήξεων της σύμβασης κλήσης της Perl και του μεγαλύτερου μέρους της ισχύος της.
Ο κανόνας ψευδωνυμοποίησης#
sub bump {
$_[0]++; # mutates the caller's variable
}
my $x = 10;
bump($x);
say $x; # 11
Η τροποποίηση του $_[0] γράφει μέσω του ψευδωνύμου σε ό,τι πέρασε ο καλών. Αυτό γίνεται σκοπίμως - είναι ο τρόπος με τον οποίο η chomp(@lines) αφαιρεί newlines από κάθε στοιχείο του @lines αντί από αντίγραφο του @lines.
Η ψευδωνυμοποίηση επεκτείνεται και στα κυριολεκτικά, με προβλέψιμες συνέπειες:
bump(10); # error: Modification of a read-only
# value attempted
Ένα κυριολεκτικό 10 είναι σταθερά. Το ψευδώνυμο δείχνει σε αυτή· η απόπειρα τροποποίησης αποτυγχάνει με die.
Το ιδίωμα αποσυσκευασίας#
Επειδή η ψευδωνυμοποίηση σπάνια είναι αυτό που θέλει το σώμα, σχεδόν κάθε sub κλασικού τύπου ξεκινά με ένα από αυτά τα δύο μοτίβα:
# Named arguments (most common)
sub greet {
my ($name, $greeting) = @_; # COPY into private lexicals
$greeting //= 'Hello';
return "$greeting, $name!";
}
# Method dispatch
sub method_call {
my $self = shift; # COPY first arg, leave rest in @_
my %args = @_; # remaining args as a hash
...
}
Μόλις αποσυσκευαστούν, το σώμα δουλεύει με ιδιωτικά αντίγραφα και δεν μπορεί να τροποποιήσει κατά λάθος την κατάσταση του καλούντος. Η shift χωρίς όρισμα μέσα σε sub χρησιμοποιεί εξ ορισμού το @_, γι” αυτό η my $self = shift; υπάρχει παντού στην OO Perl.
Νόμιμες χρήσεις ψευδωνυμοποίησης#
Η ψευδωνυμοποίηση είναι το σωστό εργαλείο όταν πραγματικά θέλετε να τροποποιήσετε την κατάσταση του καλούντος:
# in-place trim
sub trim_inplace {
for (@_) {
s/^\s+//;
s/\s+$//;
}
}
my @data = (" hello ", " world\n");
trim_inplace(@data);
# @data is now ("hello", "world")
Ο βρόχος for (@_) ψευδωνυμεί το $_ σε κάθε στοιχείο του @_, το οποίο είναι με τη σειρά του ψευδώνυμο προς κάθε στοιχείο του @data. Οι τροποποιήσεις s/// περνούν μέσα από τα δύο βήματα ψευδωνύμων στις αρχικές συμβολοσειρές. Χωρίς την ψευδωνυμοποίηση, ο ίδιος κώδικας θα ήταν διπλάσια δουλειά.
Ο ίδιος μηχανισμός τροφοδοτεί τα chomp(@lines), chop(@buf), και οποιαδήποτε συνάρτηση «επεξεργασία λίστας και επιτόπια τροποποίηση» γράφετε εσείς. Δηλώστε την πρόθεση στο όνομα της συνάρτησης (_inplace, mutate_, παρόμοια) ώστε οι καλούντες να μην αιφνιδιαστούν.
Ονομαστικά ορίσματα#
Η Perl δεν έχει ενσωματωμένη σύνταξη ονομαστικών παραμέτρων στην κλασική μορφή, αλλά ο => (fat comma) σε συνδυασμό με ανάθεση hash δίνει το ίδιο αποτέλεσμα:
sub configure {
my %opt = @_; # ('host' => 'localhost', 'port' => 8080)
$opt{host} //= 'localhost';
$opt{port} //= 80;
...
}
configure( host => 'example.com', port => 8080 );
Ο fat comma είναι σημασιολογικά ίδιος με ένα κανονικό κόμμα αλλά περικλείει σε εισαγωγικά το bareword στα αριστερά του, οπότε host => ... είναι συντομογραφία για 'host' => .... Δείτε , για τον ίδιο τον τελεστή.
Για υποχρεωτικά-και-προαιρετικά ονομαστικά ορίσματα, η τυπική μορφή είναι:
sub render {
my ($template, %opt) = @_; # one positional, rest as named
$opt{escape} //= 1;
...
}
render('greeting.tt', escape => 0, locale => 'de');
Για το σύγχρονο ιδίωμα ονομαστικών παραμέτρων βασισμένο σε υπογραφές, δείτε υπογραφές.
shift, pop, unshift, push στο @_#
Το @_ είναι ένας πραγματικός πίνακας. Μπορείτε να κάνετε shift από την αρχή, pop από το τέλος, τομή, τροποποίηση. Τίποτα από αυτά δεν αλλάζει την κατάσταση του καλούντος - μόνο η εγγραφή μέσω $_[N] το κάνει.
sub describe {
my $what = shift; # remove first arg from @_
my @rest = @_; # copy what's left
...
}
sub method {
my $self = shift;
my @args = @_;
$self->dispatch(@args);
}
Μια πρακτική συνέπεια: αν θέλετε να ξανα-πακετάρετε τα εναπομείναντα ορίσματα για προώθηση σε άλλη sub, απλώς γράψτε @_ - ακριβώς αυτό κάνει η goto &other χωρίς ρητό πέρασμα. Δείτε αναδρομή για προώθηση κλήσης ουράς.
wantarray και το περιβάλλον κλήσης#
Μέσα σε μια sub, η wantarray σας λέει το περιβάλλον στο οποίο έγινε η κλήση:
| Περιβάλλον | Τυπική μορφή |
|---|---|---|
| λίστα | επιστροφή λίστας |
| scalar | επιστροφή ενός βαθμωτού |
| κενό | πρόωρη επιστροφή· το αποτέλεσμα θα απορριφθεί |
sub items {
return unless defined wantarray; # void: nothing to compute
my @result = compute_items();
return wantarray ? @result : scalar @result;
}
Το @_ λέει τι ήρθε· η wantarray λέει τι αναμένεται πίσω. Είναι τα δύο μισά της εικόνας της σύμβασης κλήσης. Δείτε lvalue και περιβάλλον για πλήρη συζήτηση.
Συνήθεις παγίδες#
my ($x) = @_έναντιmy $x = @_. Το πρώτο είναι περιβάλλον λίστας: η$xπαίρνει το πρώτο όρισμα. Το δεύτερο είναι βαθμωτό περιβάλλον: η$xπαίρνει τον αριθμό ορισμάτων. Οι παρενθέσεις στα αριστερά κάνουν τη διαφορά· τα λάθη εδώ είναι συχνά.sub one_arg { my ($x) = @_; # $x = first arg } sub count_args { my $n = @_; # $n = number of args }
Τροποποίηση
$_[N]«κατά λάθος». Συναρτήσεις όπως ηchomp,chop,tr///,s///λειτουργούν στο όρισμά τους επιτόπια. Ηchomp($_[0])τροποποιεί τη συμβολοσειρά του καλούντος. Αν δεν είναι αυτό που θέλετε, αντιγράψτε πρώτα.Ισοπέδωση πινάκων και hashes. Πίνακες και hashes που περνιούνται ως ορίσματα χάνουν την ταυτότητά τους στο σημείο κλήσης - γίνονται όλα στοιχεία του ενιαίου επίπεδου
@_. Για να περάσετε πίνακα χωρίς ισοπέδωση, περάστε αναφορά:takes_array(\@arr); # one ref argument sub takes_array { my ($aref) = @_; push @$aref, 'extra'; }
@_μετά απόgoto &sub. Το τρέχον@_περνιέται στον στόχο. Ό,τι έχετε ήδη αφαιρέσει με shift δεν υπάρχει πλέον από την πλευρά του στόχου. Αυτό είναι χαρακτηριστικό, όχι σφάλμα - δείτε αναδρομή.
Δείτε επίσης#
@_- η εγγραφή perlvar της μεταβλητής, με τον κανόνα ψευδωνυμοποίησης και τη συζήτηση περιβάλλοντος βρόχου.Υπογραφές - η σύγχρονη εναλλακτική για χειρισμό παραμέτρων κατά θέση και ονομαστικών.
Τιμές επιστροφής - τι στέλνει πίσω το σώμα.
Τελεστής κόμματος -
=>για κατασκευή ονομαστικών ορισμάτων.