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

class#

Δηλώνει έναν χώρο ονομάτων που συμπεριφέρεται ως εγγενής κλάση αντικειμένων.

Η class εισάγει ένα νέο πακέτο όπως ακριβώς και η package, αλλά το χαρακτηρίζει ως κλάση: ο runtime προσαρτά έναν κατασκευαστή με το όνομα new, ενεργοποιεί τις δεσμευμένες λέξεις field και method μέσα στο σώμα της, και υποστηρίζει απλή κληρονομικότητα μέσω του χαρακτηριστικού :isa. Είναι η απάντηση του πυρήνα της γλώσσας στον χειροποίητο αντικειμενοστρεφή προγραμματισμό βασισμένο στο bless - το ίδιο πρόβλημα, χωρίς το επαναλαμβανόμενο πλαίσιο κώδικα.

Σημείωση

Πειραματικό Το χαρακτηριστικό class (κωδική ονομασία Corinna) είναι πειραματικό στην Perl 5.42 και μπορεί να αλλάξει με μη συμβατούς τρόπους. Ενεργοποιήστε το με use feature 'class' και αποσιωπήστε την ειδοποίηση με no warnings 'experimental::class'.

Σύνοψη#

class NAMESPACE;                          # rest-of-scope form
class NAMESPACE VERSION;
class NAMESPACE :ATTRIBUTES;
class NAMESPACE BLOCK                     # block form
class NAMESPACE VERSION BLOCK
class NAMESPACE VERSION :ATTRIBUTES BLOCK

Ελάχιστη λειτουργική κλάση:

use v5.38;
use feature 'class';
no warnings 'experimental::class';

class Point {
    field $x :param;
    field $y :param;

    method distance_from_origin {
        return sqrt($x ** 2 + $y ** 2);
    }
}

my $p = Point->new(x => 3, y => 4);
say $p->distance_from_origin;             # 5

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

Η class είναι δήλωση, όχι έκφραση - δεν επιστρέφει τιμή που μπορείτε να αναθέσετε. Αυτό που λαμβάνετε είναι:

  • Ένα νέο πακέτο στον πίνακα συμβόλων, προσπελάσιμο όπως οποιοδήποτε άλλο πακέτο.

  • Έναν παραγόμενο κατασκευαστή new. Μην γράφετε δικό σας new. Ο παραγόμενος τιμά τα χαρακτηριστικά πεδίων :param και εκτελεί κάθε μπλοκ ADJUST με τη σειρά δήλωσης.

  • Το $self δεσμεύεται έμμεσα μέσα σε κάθε σώμα method.

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

Μορφές#

Η class δέχεται τέσσερις συντακτικές μορφές. Ο διαχωρισμός μεταξύ των μορφών μπλοκ και δήλωσης αντικατοπτρίζει ακριβώς την package:

  • class NAME BLOCK - ο ορισμός της κλάσης είναι το περιεχόμενο του μπλοκ. Η εμβέλεια τερματίζει με το άγκιστρο κλεισίματος.

  • class NAME; - η υπόλοιπη τρέχουσα εμβέλεια (ή αρχείο) μέχρι την επόμενη δήλωση class ή package αποτελεί το σώμα της κλάσης. Χρήσιμο για αρχεία μίας κλάσης.

  • class NAME VERSION ... - η έκδοση δηλώνεται όπως στο package Foo 1.234. Η έκδοση πρέπει να προηγείται οποιωνδήποτε χαρακτηριστικών.

  • class NAME :ATTRIBUTES ... - ένα ή περισσότερα χαρακτηριστικά κλάσης, χωρισμένα με λευκούς χαρακτήρες, καθένα ξεκινώντας με :. Το μόνο χαρακτηριστικό κλάσης που ορίζεται προς το παρόν είναι το :isa.

class My::Thing 1.02 :isa(My::Base) {
    # body
}

Πεδία, μέθοδοι, ADJUST#

Μέσα στο σώμα μιας κλάσης τρεις νέες δεσμευμένες λέξεις βρίσκονται εντός εμβέλειας:

  • Η field δηλώνει αποθηκευτικό χώρο ανά στιγμιότυπο. Τα πεδία συμπεριφέρονται σαν λεξιλογικές μεταβλητές μέσα στις μεθόδους, αλλά κάθε στιγμιότυπο έχει τη δική του θέση. Τα χαρακτηριστικά :param, :reader και :writer παράγουν σύνδεση κατασκευαστή και προσπελαστές.

  • Η method δηλώνει μια υπορουτίνα που δεσμεύει αυτόματα το $self και που μπορεί να διαβάζει και να γράφει τα περικλείοντα πεδία με το όνομά τους. Οι μέθοδοι λειτουργούν σαν να ίσχυε το use feature 'signatures'· το $self δεν εμφανίζεται στην υπογραφή.

  • Το ADJUST BLOCK εκτελείται μετά τους αρχικοποιητές πεδίων, κατά την κατασκευή, με το $self ήδη δεσμευμένο. Χρησιμοποιήστε το για επικύρωση μετά την κατασκευή και για παράγωγα πεδία.

class Counter {
    field $value :param = 0;
    field $step  :param = 1;

    ADJUST {
        die "step must be positive" if $step <= 0;
    }

    method tick { $value += $step }
    method peek { $value }
}

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

Κληρονομικότητα: :isa#

Μια κλάση κληρονομεί από το πολύ μία άλλη κλάση:

class Shape { ... }

class Circle :isa(Shape) {
    field $r :param;
    method area { 3.14159265 * $r * $r }
}

Υποστηρίζεται μόνο απλή κληρονομικότητα. Ο στόχος του :isa φορτώνεται αυτόματα αν δεν βρίσκεται ήδη στη μνήμη - ισοδύναμο με use MODULE () πριν από τη δήλωση της κλάσης. Μπορεί να απαιτηθεί ελάχιστη έκδοση με τον ίδιο τρόπο όπως το use MODULE VERSION:

class Circle :isa(Shape 2.000) { ... }

Το :isa κληρονομεί μόνο μεθόδους. Τα πεδία είναι ιδιωτικός αποθηκευτικός χώρος ανά κλάση· μια υποκλάση δεν έχει έμμεση όψη στα πεδία της γονικής κλάσης.

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

  • %INC - το :isa(Parent) φορτώνει το Parent μέσω require κατά την πρώτη χρήση και το καταγράφει εδώ, ακριβώς όπως το use.

  • @ISA - συμπληρώνεται για την κλάση από το χαρακτηριστικό :isa, ώστε η υπάρχουσα ενδοσκόπηση isa / UNIVERSAL / SUPER:: να εξακολουθεί να λειτουργεί.

  • Ο πίνακας συμβόλων - το όνομα της κλάσης γίνεται stash στο %:: ακριβώς όπως θα δημιουργούσε η package.

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

Απλή κλάση με μια υποχρεωτική παράμετρο και ένα παράγωγο πεδίο:

class User {
    field $name :param;
    field $greeting;

    ADJUST { $greeting = "Hello, $name" }

    method greet { say $greeting }
}

User->new(name => 'Ada')->greet;          # Hello, Ada

Προεπιλεγμένες τιμές παραμέτρων - το = εφαρμόζεται όταν ο καλών παρέλειψε την παράμετρο· το //= εφαρμόζεται επίσης όταν η τιμή ήταν undef· το ||= εφαρμόζεται επίσης όταν η τιμή ήταν ψευδής:

class Window {
    field $title :param          = 'untitled';
    field $width :param          //= 640;
    field $shown :param          ||= 1;
}

Απλή κληρονομικότητα με υπερκάλυψη μεθόδου:

class Animal {
    field $name :param;
    method speak { "some sound" }
    method introduce { say $name, " says ", $self->speak }
}

class Dog :isa(Animal) {
    method speak { "woof" }
}

Dog->new(name => 'Rex')->introduce;       # Rex says woof

Ιδιωτική μέθοδος μέσω λεξιλογικού my method, η οποία καλείται μέσω ->&:

class Safe {
    field $secret :param;

    my method check ($n) { $n == $secret }

    method unlock ($n) {
        return $self->&check($n) ? "open" : "denied";
    }
}

Χρήση του __CLASS__ ώστε ένας αρχικοποιητής πεδίου της βασικής κλάσης να εντοπίζει την υπερκάλυψη της υποκλάσης:

class Base {
    sub DEFAULT_X { 10 }
    field $x = __CLASS__->DEFAULT_X;
    method x { $x }
}

class Tuned :isa(Base) {
    sub DEFAULT_X { 99 }
}

say Tuned->new->x;                         # 99

Μορφή δήλωσης για το υπόλοιπο του αρχείου:

use v5.38;
use feature 'class';
class Config;

field $path :param;
method path { $path }
# File ends here; whole remainder is Config's body.

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

  • Μην ορίζετε new. Ο παραγόμενος κατασκευαστής είναι το μόνο υποστηριζόμενο σημείο εισόδου. Ένα sub new { ... } γραμμένο από τον χρήστη μέσα σε σώμα class αποτελεί σφάλμα κατά τη μεταγλώττιση.

  • Καμία πολλαπλή κληρονομικότητα. Το :isa(A, B) είναι συντακτικό σφάλμα. Πολλαπλά χαρακτηριστικά :isa σε μία κλάση επίσης απορρίπτονται.

  • Καμία τροποποίηση του @ISA. Αντιμετωπίστε το @ISA ως μόνο για ανάγνωση για κλάσεις που δηλώνονται με class. Η προσθήκη σε αυτό κατά τον χρόνο εκτέλεσης είναι απροσδιόριστη.

  • Η package δεν μπορεί να ξανανοίξει μια κλάση. Μόλις ένας χώρος ονομάτων δηλωθεί με class, οι επόμενες δηλώσεις package που στοχεύουν το ίδιο όνομα αποτελούν σφάλμα κατά τη μεταγλώττιση, και αντιστρόφως.

  • Τα πεδία δεν είναι λεξιλογικές μεταβλητές με τη συνηθισμένη έννοια. Δεν μπορείτε να αναφερθείτε σε ένα πεδίο από έξω από το σώμα της κλάσης, και δεν μπορείτε να εφαρμόσετε our ή local σε αυτό. Μόνο μέθοδοι και μπλοκ ADJUST βλέπουν τα πεδία.

  • Το $self είναι μόνο για ανάγνωση μέσα σε μια μέθοδο. Η ανάθεση σε αυτό αποτελεί σφάλμα κατά τον χρόνο εκτέλεσης.

  • Οι αρχικοποιητές πεδίων εκτελούνται πριν υπάρξει το $self. Μέσα σε field $x = EXPR, μπορείτε να χρησιμοποιήσετε __CLASS__ και προηγουμένως δηλωμένα πεδία, αλλά όχι το $self. Οτιδήποτε χρειάζεται το πλήρως κατασκευασμένο στιγμιότυπο ανήκει σε μπλοκ ADJUST.

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

  • Επίλυση μεθόδων. Η αποστολή εξακολουθεί να γίνεται μέσω της συνήθους MRO (UNIVERSAL::isa, SUPER::), οπότε το $self->SUPER::foo(@args) λειτουργεί όπως και για κλάσεις βασισμένες στο bless.

  • Εμβέλεια μορφής δήλωσης. Η class Foo; καταναλώνει το υπόλοιπο του περικλείοντος μπλοκ - συνήθως το υπόλοιπο του αρχείου. Μια δεύτερη class ή package την τερματίζει· δεν υπάρχει τρόπος να «κλείσει» πρόωρα μια κλάση μορφής δήλωσης.

  • Πειραματική προειδοποίηση. Κάθε δήλωση class εκπέμπει μια προειδοποίηση class is experimental υπό τις προεπιλεγμένες προειδοποιήσεις. Χρησιμοποιήστε no warnings 'experimental::class' μόλις το χαρακτηριστικό μπει σε πραγματική χρήση.

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

Πλήρως συμβατό με το upstream Perl 5.42. Το χαρακτηριστικό επισημαίνεται ως πειραματικό στο upstream· η pperl αντικατοπτρίζει αυτή την κατάσταση και εκπέμπει την ίδια κατηγορία προειδοποίησης (experimental::class).

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

  • field - δηλώνει αποθηκευτικό χώρο ανά στιγμιότυπο μέσα σε σώμα class· υποστηρίζει τα :param, :reader, :writer

  • method - δηλώνει μια υπορουτίνα με έμμεσο $self και άμεση πρόσβαση στα πεδία της περικλείουσας κλάσης

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

  • bless - ο πριν την 5.38 τρόπος σύνδεσης μιας κλάσης σε μια αναφορά· εξακολουθεί να υποστηρίζεται και διαλειτουργεί με αντικείμενα κατασκευασμένα με class για ελέγχους isa/can

  • isa - τελεστής για έλεγχο μέλους κλάσης· λειτουργεί τόσο για αντικείμενα δηλωμένα με class όσο και για βασισμένα στο bless

  • use - πώς το :isa(Parent) φορτώνει τη γονική κλάση από κάτω από τα παρασκήνια