Εμβέλεια · Αρθρώματα · Κλάσεις και αντικειμενοστρέφεια

package#

Δηλώνει τον χώρο ονομάτων κατά τη μεταγλώττιση για τις δηλώσεις που ακολουθούν.

Η package λέει στον μεταγλωττιστή ποιον πίνακα συμβόλων να χρησιμοποιήσει όταν επιλύει μη προσδιορισμένα ονόματα στον κώδικα που πρόκειται να αναλύσει. Δεν δημιουργεί πακέτο με οποιαδήποτε σημασία σε χρόνο εκτέλεσης - τα πακέτα έρχονται στην ύπαρξη την πρώτη φορά που αποθηκεύεται κάτι μέσα τους. Αυτό που πραγματικά κάνει μια εντολή package είναι να αναπροσανατολίσει τον μεταγλωττιστή: από εδώ και στο εξής, το $foo σημαίνει $NAMESPACE::foo, το &bar σημαίνει &NAMESPACE::bar, και ούτω καθεξής, μέχρι την επόμενη εντολή package ή το τέλος της περικλείουσας εμβέλειας.

Σύνοψη#

package NAME;
package NAME VERSION;
package NAME     { ... }
package NAME VER { ... }

Τι επιστρέφεται#

Η package είναι οδηγία μεταγλώττισης, όχι έκφραση. Δεν έχει χρήσιμη τιμή χρόνου εκτέλεσης - αντιμετωπίστε την ως εντολή. Η επίδρασή της είναι στον αναλυτή: όλα τα μετέπειτα μη προσδιορισμένα αναγνωριστικά επιλύονται στον πίνακα συμβόλων του NAME μέχρι να τερματιστεί η εμβέλεια.

Η μορφή με VERSION έχει μία ορατή παρενέργεια: ορίζει το $NAME::VERSION σε ένα αντικείμενο version χτισμένο από το VERSION. Αυτό συμβαίνει ακριβώς μία φορά ανά εντολή package NAME VERSION, κατά τη μεταγλώττιση.

Καθολική κατάσταση που επηρεάζει#

  • Το τρέχον πακέτο μεταγλώττισης. Κάθε εντολή package το αντικαθιστά για το υπόλοιπο της εμβέλειας. Το __PACKAGE__ επιστρέφει την τρέχουσα τιμή σε οποιοδήποτε σημείο της πηγής.

  • $NAME::VERSION - ορίζεται όταν παρέχεται το όρισμα VERSION. Ορίστε το μόνο μία φορά ανά πακέτο.

  • Ο στόχος πίνακας συμβόλων (stash) δημιουργείται κατά την πρώτη χρήση. Το stash ενός πακέτου είναι το ίδιο ένα hash με όνομα %NAME:: (οπότε του main είναι το %main::), με κλειδιά τα μη προσδιορισμένα ονόματα συμβόλων που κρατά. Τίποτα δεν συμπληρώνεται από την ίδια την εντολή package· μεταγενέστερες δηλώσεις (sub, our, αναθέσεις στο $NAME::foo, κ.λπ.) το γεμίζουν.

Οι τέσσερις μορφές#

package NAMESPACE#

Αλλάζει το πακέτο μεταγλώττισης σε NAMESPACE από αυτό το σημείο μέχρι το τέλος της τρέχουσας εμβέλειας (περικλείον μπλοκ, αρχείο ή eval). Αυτή είναι η κλασική μορφή «ένα πακέτο ανά αρχείο»:

package My::Thing;

sub new { ... }         # defines &My::Thing::new
our $count = 0;         # defines $My::Thing::count

1;

package NAMESPACE VERSION#

Ίδια εμβέλεια με τη γυμνή μορφή, επιπλέον ορίζει το $NAMESPACE::VERSION σε ένα αντικείμενο version. Το VERSION πρέπει να είναι αυστηρό version literal: είτε ένας θετικός δεκαδικός (1.23, 0.001) είτε ένα v-string με τελείες που ξεκινά με v και έχει τουλάχιστον τρία τμήματα (v1.2.3). Η εκθετική σημειογραφία δεν επιτρέπεται.

package My::Thing 1.042;
package My::Thing v1.2.3;

Ορίστε το $VERSION μόνο μία φορά ανά πακέτο - μια δεύτερη εντολή package NAME VERSION στο ίδιο πακέτο αντικαθιστά την πρώτη, και οι καταναλωτές use Module VERSION βλέπουν μόνο την τελική τιμή.

package NAMESPACE BLOCK#

Περιορίζει λεξιλογικά την αλλαγή πακέτου στο BLOCK. Μέσα στα άγκιστρα το πακέτο μεταγλώττισης είναι το NAMESPACE· έξω από το άγκιστρο κλεισίματος το προηγούμενο πακέτο επαναφέρεται. Αυτή είναι η μόνη μορφή που επαναφέρεται αυτόματα.

package Outer;
our $x = 1;             # $Outer::x

package Inner {
    our $y = 2;         # $Inner::y
}

our $z = 3;             # $Outer::z again

package NAMESPACE VERSION BLOCK#

Η μορφή μπλοκ με version literal. Η εμβέλεια επαναφέρεται στο άγκιστρο κλεισίματος· το $NAMESPACE::VERSION παραμένει ορισμένο.

package My::Sub v0.9.1 {
    sub ping { "pong" }
}

Τι περιορίζει και τι δεν περιορίζει σε εμβέλεια η package#

Η package επηρεάζει τις δυναμικές μεταβλητές (πακέτου) και την επίλυση μη προσδιορισμένων ονομάτων. Δεν επηρεάζει τα λεξιλογικά:

  • my, state - δημιουργούνται στο λεξιλογικό pad, αόρατα σε αναζήτηση πακέτου. Μια εντολή package δεν τους κάνει τίποτα.

  • local - οριοθετεί δυναμικά μια μεταβλητή πακέτου, η οποία εξακολουθεί να ανήκει σε όποιο πακέτο κατονομάζει το πλήρως προσδιορισμένο όνομά της.

  • our - δηλώνει λεξιλογικό ψευδώνυμο προς μια μεταβλητή πακέτου στο τρέχον πακέτο μεταγλώττισης. Αυτός είναι ο μηχανισμός που επιτρέπει στο our $count μέσα σε package My::Thing να γίνει ψευδώνυμο του $My::Thing::count.

Η αλλαγή πακέτου μετά από δήλωση our δεν αναπροσανατολίζει το ψευδώνυμο: το ψευδώνυμο δεσμεύτηκε στο πακέτο που ίσχυε όταν μεταγλωττίστηκε η our.

package Foo;
our $x;                 # aliases $Foo::x
package Bar;
$x = 1;                 # still writes $Foo::x

Αλληλεπίδραση με την use v5.36 και νεότερες#

Η use v5.36 (και κάθε use v5.36 ή νεότερη) ενεργοποιεί έμμεσα τις strict και warnings. Μόλις τεθεί σε ισχύ η strict, οι μη προσδιορισμένες μεταβλητές πακέτου απαιτούν δήλωση our (ή πλήρη προσδιορισμό). Σε συνδυασμό με εντολή package, ο ιδιωματικός σύγχρονος σκελετός αρχείου είναι:

package My::Thing 1.00;

use v5.36;              # strict, warnings, say, signatures, ...

our @EXPORT_OK = qw(thingify);

sub thingify { ... }

1;

Η μορφή package NAME VERSION και η use VERSION είναι ανεξάρτητες: η πρώτη ορίζει το $My::Thing::VERSION· η δεύτερη ενεργοποιεί χαρακτηριστικά γλώσσας για το τρέχον αρχείο.

Ειδικά αναγνωριστικά που σημαίνουν πάντοτε main::#

Ένα μικρό σύνολο αναγνωριστικών τοποθετείται αναγκαστικά στο πακέτο main:: ανεξάρτητα από το τρέχον package:

  • STDIN, STDOUT, STDERR, ARGV, ARGVOUT

  • @ARGV, @INC, %ENV, %SIG, %INC

  • Όλες οι μεταβλητές στίξης: $_, $!, $@, @_ κ.λπ.

  • Το αναγνωριστικό ενός χαρακτήρα _, σε όλα τα sigils του: το filehandle κάτω παύλας που χρησιμοποιείται από την stat και τους ελέγχους αρχείων -X, το βαθμωτό $_, και ο πίνακας @_.

Η εγγραφή στο $! μέσα σε package Foo εξακολουθεί να γράφει στο $main::!. Αυτό είναι σκόπιμο: αυτά τα ονόματα θα ήταν άχρηστα αν μετακινούνταν με το πακέτο.

Παραδείγματα#

Ένα ελάχιστο αρχείο αρθρώματος. Το όνομα του αρχείου πρέπει να ταιριάζει με το όνομα του πακέτου (η require μεταφράζει το :: στον διαχωριστή καταλόγου):

# lib/My/Greeter.pm
package My::Greeter 1.00;
use v5.36;

sub new  { my ($cls, %a) = @_; bless { %a }, $cls }
sub greet { my $self = shift; "hello, $self->{name}\n" }

1;

Δύο πακέτα σε ένα αρχείο με τη μορφή μπλοκ. Η εμβέλεια επαναφέρεται αυτόματα, οπότε το 1; στο κάτω μέρος δεν ανήκει σε κανένα συγκεκριμένο πακέτο - αποτιμάται σε όποιο πακέτο ήταν ενεργό στην κορυφή του αρχείου (main για σενάριο, το ίδιο το πακέτο του αρχείου για άρθρωμα):

package My::Thing {
    sub do_stuff { ... }
}

package My::Thing::Helper {
    sub helper { ... }
}

Εναλλαγή μπρος-πίσω με τη μορφή εντολής - νόμιμο αλλά σπάνια αυτό που θέλετε:

package A;
sub one { 1 }           # &A::one

package B;
sub two { 2 }           # &B::two

package A;
sub three { 3 }         # &A::three

Ορισμός έκδοσης και ανάγνωσή της πίσω. Σημειώστε ότι το $VERSION είναι αντικείμενο version, όχι απλή συμβολοσειρά· μετατρέψτε σε συμβολοσειρά ή συγκρίνετε με version:

package Foo 1.23;

say $Foo::VERSION;      # 1.23
say ref $Foo::VERSION;  # version

Η our μέσα σε ένα πακέτο σάς δίνει λεξιλογικά οριοθετημένο ψευδώνυμο προς μια μεταβλητή πακέτου - ο καθιερωμένος τρόπος να δηλώνετε καθολικές σε επίπεδο αρθρώματος υπό strict:

package Counter;
use v5.36;

our $count = 0;         # aliases $Counter::count
sub bump { $count++ }

Οριακές περιπτώσεις#

  • Η package NAMESPACE VERSION δέχεται μόνο αυστηρά version literals. Η εκθετική σημειογραφία (1e3), οι μη αριθμητικές συμβολοσειρές και τα v-strings δύο τμημάτων (v1.2) αποτελούν σφάλματα μεταγλώττισης.

  • Ο διπλός ορισμός του $VERSION στο ίδιο πακέτο (είτε με δύο εντολές package NAME VERSION είτε με ρητή εκχώρηση μετά από package NAME VERSION) είναι νόμιμος αλλά μπερδεύει - η use Module VERSION ελέγχει την τελική τιμή, ενώ τα εργαλεία του CPAN διαβάζουν όποια βρουν πρώτη. Δηλώστε την έκδοση μία φορά.

  • Η μορφή μπλοκ είναι ξεχωριστή λεξιλογική εμβέλεια. Οι μεταβλητές my και state που δηλώνονται μέσα σε package NAME { ... } δεν είναι ορατές απ” έξω, όπως και σε οποιοδήποτε άλλο μπλοκ.

  • Η package NAMESPACE χωρίς ακολουθούσα εντολή ή μπλοκ επηρεάζει το υπόλοιπο του αρχείου. Μια package στην κορυφή ενός σεναρίου μετακινεί μόνιμα το σενάριο εκτός του main, που σημαίνει ότι το $main::ARGV[0] εξακολουθεί να είναι η λίστα ορισμάτων σας αλλά οι νεοδηλωμένες καθολικές ανήκουν στο νέο πακέτο. Σχεδόν ποτέ ένα σενάριο δεν θέλει αυτό.

  • Ένα αρχείο που περιέχει μόνο package Foo; και κανέναν άλλο κώδικα εξακολουθεί να μεταγλωττίζεται καθαρά και να δημιουργεί το stash Foo:: στην πρώτη αναφορά - αλλά το require σε αυτό επιστρέφει την τιμή της τελευταίας εντολής, που είναι η ίδια η εντολή package (ψευδής). Βάλτε 1; στο τέλος κάθε αρχείου αρθρώματος.

  • Εμφωλευμένες μορφές μπλοκ επαναφέρουν το άμεσα περικλείον πακέτο, όχι το main:

    package Outer;
    package Inner {
        package Innermost {
            # __PACKAGE__ is Innermost
        }
        # __PACKAGE__ is Inner again
    }
    # __PACKAGE__ is Outer again
    
  • Η package μέσα σε eval. Η αλλαγή πακέτου περιορίζεται στο σώμα της eval. Τα σύμβολα που δημιουργήθηκαν κατά την eval παραμένουν στα stashes τους (τα stashes είναι καθολικά), αλλά το πακέτο μεταγλώττισης επανέρχεται όταν τελειώσει η eval.

  • Απόστροφος ως διαχωριστής πακέτου. Ο απόστροφος ήταν ο αρχικός διαχωριστής χώρου ονομάτων της Perl: το $main'sail σήμαινε $main::sail, πολύ πριν υπάρξει το ::. Επιβιώνει μόνο για την ανάγνωση κώδικα εποχής Perl 4 και είναι απενεργοποιημένος υπό τα σύγχρονα πακέτα χαρακτηριστικών, οπότε ένα τρέχον πρόγραμμα γραμμένο με use v5.36 (ή οποιοδήποτε πρόσφατο πακέτο) δεν θα τον αναγνωρίσει. Μην τον γράφετε· η διπλή άνω-κάτω τελεία :: είναι ο μόνος διαχωριστής που πρέπει να χρησιμοποιεί ο τρέχων κώδικας.

Διαφορές από το upstream#

Πλήρως συμβατό με το upstream Perl 5.42.

Δείτε επίσης#

  • use - φορτώνει ένα άρθρωμα κατά τη μεταγλώττιση και εισάγει σύμβολα από το πακέτο του· συνήθως συνοδεύεται από δήλωση package στην κορυφή του φορτωμένου αρχείου

  • require - φορτώνει άρθρωμα ή αρχείο σε χρόνο εκτέλεσης· η εντολή package του φορτωμένου αρχείου καθορίζει ποιο stash γεμίζουν οι δηλώσεις του

  • bless - συσχετίζει μια αναφορά με ένα πακέτο ώστε οι κλήσεις μεθόδων να διανέμονται στις υπορουτίνες εκείνου του πακέτου· η συγκολλητική ύλη μεταξύ package και αντικειμενοστρέφειας

  • my - δηλώνει λεξιλογική μεταβλητή που η package δεν επηρεάζει· το αντίστοιχο των καθολικών πακέτου

  • our - δηλώνει λεξιλογικό ψευδώνυμο προς μεταβλητή πακέτου στο τρέχον πακέτο μεταγλώττισης· ο strict-safe τρόπος να χρησιμοποιείτε καθολικές σε επίπεδο αρθρώματος

  • local - οριοθετεί δυναμικά την τιμή μιας μεταβλητής πακέτου χωρίς να αλλάζει σε ποιο πακέτο ανήκει