SUB#
Επιστρέφει μια αναφορά στην υπορουτίνα που εκτελείται τη δεδομένη στιγμή.
Το __SUB__ είναι το σύμβολο αυτο-αναφοράς: μέσα σε μια sub, αποτιμάται σε μια αναφορά κώδικα που δείχνει σε αυτήν την ίδια sub, χωρίς η sub να χρειάζεται να γνωρίζει το όνομά της. Εκτός κάθε sub, είναι undef. Ο συνηθισμένος λόγος για την προσφυγή σε αυτό είναι η ανώνυμη αναδρομή - μια sub αποθηκευμένη σε λεξιλογική μεταβλητή ή που περνά ως callback χρειάζεται έναν τρόπο να καλέσει τον εαυτό της που δεν εξαρτάται από όνομα κατονομασμένο πλήρως με πακέτο, και το __SUB__ είναι αυτός ο τρόπος.
Σύνοψη#
__SUB__
__SUB__->(@args)
goto __SUB__
Δεν δέχεται ορίσματα και δεν έχει μορφή με παρενθέσεις - είναι σύμβολο κατά τη μεταγλώττιση, όχι κλήση συνάρτησης.
Τι επιστρέφεται#
Μια αναφορά κώδικα (το ίδιο πράγμα που θα σας έδινε το \&name για μια κατονομασμένη sub), ή undef όταν αποτιμάται εκτός οποιασδήποτε υπορουτίνας. Η αναφορά είναι προς την sub σε χρόνο εκτέλεσης, συμπεριλαμβανομένης κάθε closure πάνω σε λεξιλογικές μεταβλητές που αποτυπώθηκαν όταν δημιουργήθηκε η sub, οπότε η αναδρομική κλήση της βλέπει το ίδιο αποτυπωμένο περιβάλλον.
my $fact = sub {
my $n = shift;
$n < 2 ? 1 : $n * __SUB__->($n - 1);
};
print $fact->(5); # 120
Η μορφή κλήσης είναι μια συνηθισμένη επίκληση coderef: __SUB__->(@args) ή &{__SUB__}(@args). Κανένα όρισμα δεν περνά σιωπηρά· η αναδρομή πρέπει να τα προωθεί ρητά.
Γιατί να μη χρησιμοποιήσουμε απλώς το όνομα της sub#
Οι κατονομασμένες subs μπορούν ήδη να εκτελούν αναδρομή με το όνομά τους - το factorial(...) μέσα στη sub factorial δουλεύει. Το __SUB__ δικαιολογεί τη θέση του σε τρεις περιπτώσεις όπου ένα όνομα δεν είναι διαθέσιμο, αξιόπιστο ή ακριβό:
Ανώνυμες subs. Μια ανώνυμη sub που εκχωρείται σε λεξιλογική μεταβλητή δεν έχει σταθερό όνομα κατονομασμένο με πακέτο. Ένας συνηθισμένος τρόπος παράκαμψης πριν την 5.16 ήταν η αποτύπωση μιας αναφοράς προς
\&nameή η χρήση κόλπωνY-combinator· το__SUB__αντικαθιστά και τα δύο.Subs που περνούν ως callbacks. Μια sub που παραδίδεται σε ένα άλλο API (συγκριτής ταξινόμησης, χειριστής συμβάντων, βήμα επαναλήπτη) ενδέχεται να κληθεί πίσω προτού αποκτήσει όνομα ορατό στο σημείο της αναδρομής.
Αναδρομή με κλήση ουράς μέσω
goto. Τοgoto __SUB__επαναχρησιμοποιεί το τρέχον πλαίσιο κλήσης και μεταπηδά στην κορυφή της ίδιας sub με όποια τιμή του@_έχετε ρυθμίσει, κάτι που έχει σημασία για βαθιά αναδρομή που διαφορετικά θα ανατίναζε τη στοίβα.
Καθολική κατάσταση που επηρεάζει#
Το __SUB__ διαβάζει το πλαίσιο κλήσης που εκτελείται τη δεδομένη στιγμή - το ίδιο πλαίσιο που επιθεωρεί ο caller. Δεν διαβάζει ούτε τροποποιεί ειδικές μεταβλητές.
Παραδείγματα#
Ανώνυμο παραγοντικό, η σχολική περίπτωση:
my $fact = sub {
my $n = shift;
$n < 2 ? 1 : $n * __SUB__->($n - 1);
};
print $fact->(6); # 720
Άθροισμα με αναδρομή ουράς μέσω goto __SUB__ - χωρίς αύξηση στοίβας ανά επανάληψη, επειδή το goto επαναχρησιμοποιεί το τρέχον πλαίσιο:
my $sum = sub {
my ($acc, @rest) = @_;
return $acc unless @rest;
@_ = ($acc + shift @rest, @rest);
goto __SUB__;
};
print $sum->(0, 1..1_000_000); # 500000500000
Διάσχιση εμφωλευμένης δομής δεδομένων χωρίς να κατονομαστεί ο διασχιστής:
my $count_leaves = sub {
my $node = shift;
return 1 unless ref $node eq 'ARRAY';
my $n = 0;
$n += __SUB__->($_) for @$node;
return $n;
};
print $count_leaves->([1, [2, 3], [[4], 5]]); # 5
Εκτός οποιασδήποτε sub, το __SUB__ είναι undef:
print defined(__SUB__) ? "yes" : "no"; # no
Αποτυπωμένο, όχι αναλυόμενο κατά την κλήση. Το __SUB__ αποτιμάται κάθε φορά που εκτελείται, στο πλαίσιο εντός του οποίου εκτελείται - έτσι σε μια εμφωλευμένη sub αναφέρεται στην εσωτερική sub:
sub outer {
my $inner = sub { __SUB__ }; # inner's own coderef
return $inner->();
}
my $ref = outer();
print $ref == $ref; # 1 - stable coderef
Οριακές περιπτώσεις#
Απαιτεί το χαρακτηριστικό
current_sub. Το__SUB__βρίσκεται πίσω απόuse feature 'current_sub', ενεργοποιημένο εξ ορισμού υπόuse v5.16ή οποιοδήποτε μεταγενέστερο πακέτο εκδόσεων. Κώδικας που στοχεύει παλαιότερα επίπεδα σύνταξης πρέπει να το ενεργοποιήσει ρητά, ή να προθέσει στο σύμβολο τοCORE::ωςCORE::__SUB__.Χωρίς μορφή με παρενθέσεις. Το
__SUB__()είναι συντακτικό σφάλμα - το σύμβολο δεν είναι συνάρτηση, είναι δεσμευμένη λέξη που αποτιμάται σε coderef. Καλέστε το αποτέλεσμα με__SUB__->()ή&{__SUB__}().Εκτός οποιασδήποτε sub, συμπεριλαμβανομένης της εμβέλειας αρχείου και του εσωτερικού των μπλοκ
BEGIN,UNITCHECK,CHECK,INITκαιEND, το__SUB__επιστρέφειundef. Η κλήση του (__SUB__->()) σε αυτές τις θέσεις πεθαίνει μεCan't use an undefined value as a subroutine reference.Μέσα σε μπλοκ
eval, το__SUB__αναφέρεται στην περικλείουσα sub, όχι στηνeval- έναeval { ... }δεν δημιουργεί νέο πλαίσιο sub για αυτόν τον σκοπό. Μέσα σεeval EXPRισχύει ο ίδιος κανόνας: το σύμβολο αναλύεται στην εξωτερική sub.Μέσα σε μπλοκ κώδικα regex (
/(?{...})/ή/(??{...})/), η συμπεριφορά του__SUB__υπόκειται σε αλλαγές - το upstream το τεκμηριώνει ως ασταθές. Μη βασίζεστε σε αυτό που επιστρέφει εκεί.Ταυτότητα μεταξύ κλήσεων. Δύο αποτιμήσεις του
__SUB__μέσα στην ίδια sub επιστρέφουν το ίδιο coderef (η==συγκρίνει ως αληθής). Μεταξύ διαφορετικών closures που φτιάχνονται από το ίδιοsub { ... }, κάθε closure βλέπει το δικό του coderef - ένα ανά αποτυπωμένο περιβάλλον.goto __SUB__έναντι__SUB__->(). Η μορφήgotoεπαναχρησιμοποιεί το τρέχον πλαίσιο κλήσης και αντικαθιστά το@_με ό,τι αναθέσατε πριν τοgoto· δεν μεγαλώνει τη στοίβα κλήσεων. Η μορφή κλήσης coderef δημιουργεί νέο πλαίσιο κάθε φορά, οπότε χτυπά το όριο βάθους αναδρομής σε βαθιά αναδρομικές εισόδους.
Διαφορές από το upstream#
Πλήρως συμβατό με το upstream Perl 5.42.
Δείτε επίσης#
sub- ορίζει την υπορουτίνα της οποίας την αναφορά επιστρέφει το__SUB__· το πρώτο μέρος που πρέπει να κοιτάξετε όταν η ανώνυμη αναδρομή είναι το εργαλείο για τη δουλειάgoto- συνεργάζεται με το__SUB__για αναδρομή με κλήση ουράς μέσωgoto __SUB__, το ιδίωμα που αποφεύγει την αύξηση της στοίβαςcaller- επιθεώρηση του ίδιου πλαισίου κλήσης από έξω (πακέτο, αρχείο, γραμμή) αντί για λήψη αναφοράς σε αυτόref- κατηγοριοποίηση αυτού που επέστρεψε το__SUB__· πάντα"CODE"μέσα σε sub, κενή συμβολοσειρά εκτόςreturn- ο συνηθισμένος τρόπος εξόδου από τη sub της οποίας η αναφορά είναι το__SUB__· σχετικός όταν επιλέγει κανείς μεταξύ αναδρομής και κλήσης ουράς μέσωgoto __SUB__