Κλάσεις και αντικειμενοστρέφεια

bless#

Σημαδεύει αυτό στο οποίο δείχνει μια αναφορά ως αντικείμενο σε ένα πακέτο.

Η bless συνδέει τον αναφερόμενο της REF με το πακέτο που κατονομάζει το CLASSNAME, ώστε οι κλήσεις μεθόδων μέσω της REF να αποστέλλονται στις υπορουτίνες αυτού του πακέτου (και στους προγόνους του στο @ISA). Η ίδια η αναφορά δεν αλλάζει· αυτό που αλλάζει είναι η ετικέτα κλάσης του αναφερόμενου. Η bless επιστρέφει την REF, γι” αυτό είναι σχεδόν πάντα η τελευταία εντολή σε έναν κατασκευαστή.

Σύνοψη#

bless REF, CLASSNAME
bless REF

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

Την ίδια αναφορά που πέρασε ως πρώτο όρισμα, η οποία τώρα φέρει την ετικέτα κλάσης CLASSNAME. Η επιστροφή της αναφοράς σας επιτρέπει να καλέσετε την bless ως τελική κλήση από έναν κατασκευαστή:

sub new {
    my ($class, %args) = @_;
    return bless { %args }, $class;
}

Από εκείνο το σημείο και μετά, η ref επί της επιστρεφόμενης αναφοράς αποδίδει το όνομα κλάσης αντί για τον ακατέργαστο τύπο αναφοράς (HASH, ARRAY, CODE, …).

Μορφές#

Δύο μορφές κλήσης, η μία ισχυρά προτιμώμενη:

  • Δύο ορισμάτων - χρησιμοποιήστε πάντα αυτή.

    bless $ref, $class;
    

    Ο αναφερόμενος γίνεται αντικείμενο στο πακέτο που κατονομάζει η $class. Η χρήση του πρώτου ορίσματος του κατασκευαστή ($_[0], συμβατικά $class) διατηρεί τον κατασκευαστή κληρονομήσιμο: μια υποκλάση που καλεί Parent::new('Child', ...) λαμβάνει πίσω ένα αντικείμενο blessed στο Child, όχι στο Parent.

  • Δύο ορισμάτων με κενή συμβολοσειρά - bless στο main.

    bless $ref, "";
    

    Ένα κενό CLASSNAME αντιμετωπίζεται ως το πακέτο main. Σπάνια χρήσιμο εκτός από σκόπιμα τεχνάσματα.

  • Ενός ορίσματος - αποθαρρύνεται.

    bless $ref;
    

    Ο αναφερόμενος γίνεται bless στο τρέχον πακέτο (το πακέτο στο οποίο μεταγλωττίζεται η κλήση bless). Αυτό σπάει την κληρονομικότητα: μια υποκλάση που κληρονομεί έναν κατασκευαστή bless ενός ορίσματος καταλήγει εξακολουθητικά με αντικείμενα στο πακέτο του γονέα, όχι του καλούντος. Χρησιμοποιήστε τη μορφή δύο ορισμάτων εκτός εάν έχετε συγκεκριμένο λόγο να μην το κάνετε, και τεκμηριώστε τον λόγο.

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

Μια ελάχιστη κλάση βασισμένη σε κατακερματισμό:

package Point;

sub new {
    my ($class, $x, $y) = @_;
    return bless { x => $x, y => $y }, $class;
}

sub x { $_[0]->{x} }
sub y { $_[0]->{y} }

package main;

my $p = Point->new(3, 4);
print ref $p, "\n";       # Point
print $p->x, ",", $p->y;  # 3,4

Κληρονομήσιμος κατασκευαστής - η ίδια new λειτουργεί για υποκλάση χωρίς τροποποίηση:

package Shape;
sub new {
    my ($class, %args) = @_;
    return bless { %args }, $class;
}

package Circle;
our @ISA = ('Shape');
sub area {
    my $self = shift;
    return 3.14159 * $self->{radius} ** 2;
}

package main;
my $c = Circle->new(radius => 5);
print ref $c, "\n";       # Circle
print $c->area, "\n";     # 78.53975

Τα αντικείμενα βασισμένα σε πίνακα λειτουργούν με τον ίδιο τρόπο - οποιοσδήποτε τύπος αναφοράς μπορεί να γίνει bless:

package Pair;
sub new {
    my ($class, $a, $b) = @_;
    return bless [$a, $b], $class;
}
sub first  { $_[0]->[0] }
sub second { $_[0]->[1] }

my $p = Pair->new("left", "right");
print $p->first, "/", $p->second;   # left/right

Η εκ νέου bless ενός υπάρχοντος αντικειμένου αλλάζει την ετικέτα κλάσης του επιτόπου:

my $obj = bless {}, 'OldClass';
bless $obj, 'NewClass';
print ref $obj;            # NewClass

Η bless επιστρέφει την αναφορά, γι” αυτό λειτουργεί η αλυσίδωση σε κλήσεις μεθόδων στην ίδια γραμμή:

Logger->new(file => $path)->info("started");
#                              ^ called on the blessed ref

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

  • Αυτό που λαμβάνει την ετικέτα είναι η αναφορά, όχι η μεταβλητή. Τα αντίγραφα της αναφοράς μοιράζονται την ετικέτα κλάσης επειδή όλα δείχνουν στον ίδιο αναφερόμενο:

    my $a = bless {}, 'Foo';
    my $b = $a;
    print ref $b;            # Foo
    
  • Η εκ νέου bless επιτρέπεται και είναι άμεση. Μια αναφορά μπορεί να γίνει bless όσες φορές θέλετε· κάθε κλήση γράφει πάνω από την προηγούμενη ετικέτα κλάσης. Δεν υπάρχει ενσωματωμένη «unbless» - κάντε rebless σε ένα ουδέτερο πακέτο αν χρειάζεται να αφαιρέσετε την αντικειμενική φύση από έναν αναφερόμενο στον οποίο εξακολουθείτε να διατηρείτε αναφορές.

  • CLASSNAME ίσο με "" σημαίνει main. Ρητό και σπάνια επιθυμητό· συνήθως ένδειξη ότι ένα υπολογισμένο όνομα κλάσης βγήκε κενό κατά λάθος.

  • Αποφύγετε το bless $ref, "0". Το όνομα κλάσης "0" είναι ψευδής τιμή, οπότε κώδικας που ελέγχει if (ref $obj) { ... } θα διαβάσει εσφαλμένα το αντικείμενο ως «μη αναφορά». Επιλέξτε οποιοδήποτε όνομα κλάσης που δεν είναι ψευδές.

  • Σύμβαση πεζών-κεφαλαίων για ονόματα κλάσεων. Χρησιμοποιήστε ανάμεικτη γραφή (My::Package). Τα ονόματα με ΟΛΟΚΕΦΑΛΑΙΑ είναι δεσμευμένα για ενσωματωμένους τύπους της Perl (SCALAR, ARRAY, HASH, CODE, …) και τα ονόματα μόνο με πεζά είναι δεσμευμένα για pragmas (strict, warnings, utf8). Το bless σε οποιονδήποτε από αυτούς τους χώρους ονομάτων προκαλεί σύγχυση με τον μηχανισμό σε επίπεδο γλώσσας.

  • Πρώτο όρισμα που δεν είναι αναφορά αποτελεί μοιραίο σφάλμα. Το bless 42, 'Foo' πεθαίνει με Can't bless non-reference value. Το πρώτο όρισμα πρέπει να είναι αναφορά.

  • Η bless ενός ορίσματος επιλέγει το πακέτο μεταγλώττισης. Χρησιμοποιεί το πακέτο μέσα στο οποίο βρίσκεται λεξιλογικά η κλήση bless - όχι το πακέτο του καλούντος, όχι το πακέτο της $class. Αυτός ακριβώς είναι ο λόγος που σπάει την κληρονομικότητα και που υπάρχει η μορφή δύο ορισμάτων.

  • Οι ασθενείς αναφορές και το bless αλληλεπιδρούν όπως αναμένεται. Η Scalar::Util::weaken σε μια blessed αναφορά δεν την αποκαθιστά· η εξασθενημένη θυρίδα εξακολουθεί να βλέπει την ετικέτα κλάσης, και η ref λειτουργεί μέχρι να καταστραφεί ο αναφερόμενος.

  • Η DESTROY εκπυρσοκροτεί στον blessed αναφερόμενο. Όταν η τελευταία αναφορά σε έναν blessed αναφερόμενο εξαφανιστεί, η Perl καλεί την DESTROY στην κλάση της αναφοράς (ακολουθώντας το @ISA). Η αλλαγή της κλάσης με μια καθυστερημένη bless αλλάζει ποια DESTROY εκτελείται.

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

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

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

  • ref - διαβάστε πίσω την ετικέτα κλάσης από μια blessed αναφορά, ή τον τύπο αναφοράς (HASH, ARRAY, …) για μια μη-blessed

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

  • class - η πειραματική ενσωματωμένη σύνταξη κλάσης που αντικαθιστά το χειρωνακτικά γραμμένο μοτίβο κατασκευαστή package + bless με δηλωτική σύνταξη

  • tie - μια διαφορετική μορφή μαγείας ανά μεταβλητή· άσχετη με την bless παρά την επιφανειακή διατύπωση «επισύναψη συμπεριφοράς σε μια τιμή»

  • @ISA - η αλυσίδα κληρονομικότητας που συμβουλεύεται κατά την αποστολή μιας κλήσης μεθόδου σε blessed αναφορά

  • DESTROY - η μέθοδος καταστροφέα που η Perl καλεί στον blessed αναφερόμενο όταν εξαφανιστεί η τελευταία του αναφορά· δηλώνεται ως υπορουτίνα μέσα στο πακέτο της κλάσης