wantarray#
Αναφέρει το περιβάλλον κλήσης της υπορουτίνας που εκτελείται τη δεδομένη στιγμή.
Η wantarray επιτρέπει σε μια υπορουτίνα να ρωτήσει τον runtime πώς έγραψε την κλήση ο καλών της: ανατέθηκε το αποτέλεσμα σε λίστα, σε βαθμωτό, ή πετάχτηκε; Η απάντηση είναι μία από τρεις διακριτές τιμές, και μια υπορουτίνα μπορεί να τη χρησιμοποιήσει για να επιστρέψει διαφορετικά σχήματα δεδομένων, ή να παρακάμψει εντελώς δαπανηρή εργασία όταν ο καλών δεν ζήτησε τίποτα.
Σύνοψη#
wantarray
Δεν λαμβάνει ορίσματα και δεν έχει μορφή με παρενθέσεις - είναι δεσμευμένη λέξη, όχι κλήση συνάρτησης.
Τι επιστρέφεται#
Η wantarray επιστρέφει μία από ακριβώς τρεις τιμές, που αντιστοιχούν στα τρία περιβάλλοντα που διακρίνει η Perl:
Τιμή επιστροφής | Περιβάλλον του καλούντος | Τυπική σύνταξη καλούντος |
|---|---|---|
αληθές ( | λίστα |
|
ψευδές ( | βαθμωτό |
|
κενό |
|
Η τριμερής διάκριση είναι ο λόγος που η συνάρτηση «θα έπρεπε να είχε ονομαστεί wantlist()»: η φαινομενικά λογική τιμή επιστροφής είναι στην πραγματικότητα τριών καταστάσεων, και το defined wantarray είναι ο σωστός έλεγχος για το «θέλησε καθόλου τίποτα ο καλών».
Ο κανονικός ιδιωματισμός#
Το μοτίβο για το οποίο υπάρχει η wantarray είναι υπορουτίνα που προσαρμόζει το σχήμα επιστροφής της στον καλούντα:
sub records {
my @rows = heavy_query();
return wantarray ? @rows : "@rows";
}
my @r = records(); # gets the list
my $s = records(); # gets a space-joined string
records(); # still runs heavy_query - see below
Συνδυάστε το με πρόωρη έξοδο όταν ο καλών δεν ζήτησε τίποτα:
sub records {
return unless defined wantarray; # caller wrote `records();`
my @rows = heavy_query(); # skipped in void context
return wantarray ? @rows : "@rows";
}
Το defined wantarray είναι ο φύλακας κενού περιβάλλοντος. Η wantarray μόνη της δεν είναι - είναι ψευδής τόσο σε βαθμωτό όσο και σε κενό περιβάλλον, και πρόωρο return σε ψευδή wantarray θα έσπαζε κάθε καλούντα βαθμωτού περιβάλλοντος.
Το περιβάλλον διαδίδεται, δεν επανερμηνεύεται#
Η wantarray αναφέρει το περιβάλλον που επέβαλε ο καλών στην υπορουτίνα, όχι τι κάνει εσωτερικά η υπορουτίνα:
sub ctx { wantarray ? "list" : defined wantarray ? "scalar" : "void" }
my @a = ctx(); # "list"
my $s = ctx(); # "scalar"
ctx(); # "void"
print ctx(), "\n"; # "list" - print's LIST is list context
scalar ctx(); # "scalar" - scalar() forces scalar context
Παρατηρήστε τα δύο τελευταία: η print επιβάλλει περιβάλλον λίστας στα ορίσματά της, και η scalar επιβάλλει ρητά βαθμωτό περιβάλλον. Κανένα δεν αφορά το τι κάνει η ctx με το αποτέλεσμα.
Κλήσεις από κενό περιβάλλον#
Μια υπορουτίνα που καλείται ως γυμνή εντολή εκτελείται σε κενό περιβάλλον, και η wantarray επιστρέφει undef μέσα σε εκείνη την υπορουτίνα. Αυτό δεν διαδίδεται προς τα κάτω: μια υπορουτίνα που καλείται μέσα από υπορουτίνα κενού περιβάλλοντος βλέπει όποιο περιβάλλον επέβαλε ο δικός της καλών.
sub inner { defined wantarray ? "wanted" : "void" }
sub outer { my $x = inner(); return $x }
outer(); # outer is void; inner is scalar → "wanted"
Κάθε σημείο κλήσης καθιερώνει το δικό του περιβάλλον ανεξάρτητα. Η wantarray αναφέρει πάντα το περιβάλλον της κοντινότερης περικλείουσας υπορουτίνας, όχι της δυναμικής αλυσίδας.
Λειτουργεί επίσης μέσα σε eval#
Η wantarray αναφέρει επίσης το περιβάλλον μπλοκ eval ή eval EXPR, όχι μόνο ονοματισμένων υπορουτινών:
my @x = eval { wantarray ? (1, 2, 3) : "scalar" }; # (1,2,3)
my $x = eval { wantarray ? (1, 2, 3) : "scalar" }; # "scalar"
eval { defined wantarray ? 1 : 0 }; # void → 0
Είναι ο ίδιος μηχανισμός - το eval είναι πλαίσιο κλήσης με την ίδια έννοια που είναι μια υπορουτίνα.
Πού η wantarray δεν έχει χρήσιμη απάντηση#
Το αποτέλεσμα της wantarray είναι απροσδιόριστο σε αυτά τα μέρη, και ο κώδικας δεν πρέπει να βασίζεται σε κάποια συγκεκριμένη τιμή:
Στο ανώτατο επίπεδο ενός αρχείου (έξω από οποιαδήποτε υπορουτίνα).
Μέσα σε μπλοκ
BEGIN,UNITCHECK,CHECK,INIT, ήEND.Μέσα σε μέθοδο
DESTROY.
Αντιμετωπίστε την wantarray ως νοηματική μόνο μέσα σε συνηθισμένη υπορουτίνα ή eval. Οπουδήποτε αλλού, σχεδιάστε τον κώδικά σας ώστε η απάντηση να μην έχει σημασία.
Παραδείγματα#
Ένας getter που επιστρέφει την πλήρη λίστα σε καλούντες λίστας, το πλήθος σε καλούντες βαθμωτού, και δεν κάνει τίποτα σε κενό περιβάλλον:
sub warnings {
return unless defined wantarray;
my @w = collect_warnings();
return wantarray ? @w : scalar @w;
}
my @all = warnings(); # every warning
my $count = warnings(); # just the number
warnings(); # collect_warnings() is not called
Μια υπορουτίνα που αρνείται να κληθεί σε κενό περιβάλλον επειδή η τιμή επιστροφής είναι όλο το νόημα:
sub must_use {
defined wantarray
or croak "must_use: return value must be used";
return compute();
}
Μια υπορουτίνα που εκπέμπει ένα στοιχείο ανά κλήση σε βαθμωτό περιβάλλον και ολόκληρη τη δέσμη σε περιβάλλον λίστας - σχήμα που εκθέτουν ορισμένα APIs τύπου iterator:
sub next_batch {
state @queue;
@queue = refill() unless @queue;
return wantarray ? splice(@queue) : shift @queue;
}
Οριακές περιπτώσεις#
Καμία παρένθεση, κανένα όρισμα. Το
wantarray()αναλύεται αλλά οι κενές παρενθέσεις είναι θόρυβος· η δεσμευμένη λέξη δεν παίρνει τίποτα. Τοwantarray $xείναι συντακτικό σφάλμα, όχι κλήση με όρισμα.Όχι το περιβάλλον του καλούντος για τελεστές. Η
wantarrayαναφέρει μόνο το περιβάλλον πλαισίου κλήσης. Μια έκφραση όπως$sub->() + 1βάζει την κλήση σε βαθμωτό περιβάλλον· ηwantarrayμέσα στο$subβλέπει βαθμωτό, όπως αναμένεται. Δεν υπάρχει τρόπος να ρωτήσετε «κλήθηκα μέσα σε αριθμητική έκφραση;» - μόνο λίστα / βαθμωτό / κενό.Η
returnτιμά το ίδιο περιβάλλον. Τοreturn @listσε βαθμωτό περιβάλλον αποδίδει το τελευταίο στοιχείο, όχι το πλήθος - επειδή η ίδια ηreturnβλέπει το περιβάλλον του καλούντος. Χρησιμοποιήστεreturn wantarray ? @list : scalar @listόταν θέλετε το πλήθος για καλούντες βαθμωτού.Το λογικό περιβάλλον είναι βαθμωτό περιβάλλον. Το
if (f())καλεί τηνfσε βαθμωτό περιβάλλον· ηwantarrayεκεί επιστρέφει ψευδές, όχιundef.Η ανάθεση λίστας σε κενή λίστα παραμένει περιβάλλον λίστας. Το
() = f();είναι περιβάλλον λίστας παρόλο που το αποτέλεσμα απορρίπτεται. Ηwantarrayεπιστρέφει αληθές. Αυτό είναι χρήσιμο για επιβολή περιβάλλοντος λίστας σε υπορουτίνα της οποίας οι παρενέργειες εξαρτώνται από αυτό.Η
wantarrayδεν είναι διαθέσιμη σε καλούντες XS με τον ίδιο τρόπο. Ένα XSUB ελέγχει το περιβάλλον μέσω τουGIMME_V· μια υπορουτίνα Perl που καλείται από XSUB βλέπει το περιβάλλον που το XSUB καθιέρωσε για την κλήση.Τα πρωτότυπα δεν αλλάζουν την
wantarray. Ένα πρωτότυπο($)επιβάλλει το περιβάλλον ενός ορίσματος, όχι το ίδιο το περιβάλλον κλήσης της υπορουτίνας.
Διαφορές από το upstream#
Πλήρως συμβατό με το upstream Perl 5.42.
Δείτε επίσης#
return- τιμά το ίδιο περιβάλλον λίστας/βαθμωτού/κενού που αναφέρει ηwantarray· τα δύο σχεδιάζονται για να χρησιμοποιούνται μαζίcaller- ελέγχει την ίδια τη στοίβα κλήσεων (πακέτο, αρχείο, γραμμή, και, στη μορφή τριών ορισμάτων, περισσότερες λεπτομέρειες περιβάλλοντος συμπεριλαμβανομένου του αν ηwantarrayθα επέστρεφε αληθές εκεί)scalar- επιβάλλει βαθμωτό περιβάλλον σε μια έκφραση, που είναι αυτό που κάνει τηνwantarrayνα επιστρέφει ψευδές στον καλούμενοeval- καθιερώνει πλαίσιο κλήσης του οποίου το περιβάλλον αναφέρει επίσης ηwantarray