Εμβέλεια · Κλάσεις και αντικειμενοστρέφεια
field#
Δηλώνει μια μεταβλητή ανά στιγμιότυπο μέσα σε ένα μπλοκ class.
Η field εισάγει μια νέα μεταβλητή της οποίας η αποθήκευση είναι ιδιωτική σε κάθε αντικείμενο της περικλείουσας κλάσης. Κάθε μέθοδος και κάθε μπλοκ ADJUST αυτής της κλάσης βλέπει το πεδίο σαν να ήταν μια λεξιλογική μεταβλητή σε εμβέλεια σε εκείνο το σημείο - αλλά η τιμή που βλέπει η καθεμιά είναι η τιμή που ανήκει στο τρέχον στιγμιότυπο. Τα πεδία αντικαθιστούν, στο πλαίσιο του χαρακτηριστικού class, την παρακολούθηση θέσεων hash σε μια blessed αναφορά.
Το χαρακτηριστικό εξακολουθεί να σημαίνεται ως πειραματικό στην Perl 5.42 (δείτε Διαφορές από το upstream)· ενεργοποιήστε το με use feature 'class'; και σιγάστε την κατηγορία προειδοποίησης με no warnings 'experimental::class'; αν δεν θέλετε τον θόρυβο.
Σύνοψη#
field $scalar;
field $scalar = EXPR;
field @array : ATTRIBUTES;
field %hash : ATTRIBUTES = EXPR;
Τι επιστρέφεται#
Η field είναι δήλωση, όχι έκφραση. Δεν παράγει τιμή και δεν μπορεί να εμφανιστεί στη δεξιά πλευρά οτιδήποτε. Κάθε εντολή field δεσμεύει μία θέση ανά στιγμιότυπο στη διάταξη της κλάσης· η θέση είναι η ίδια η μεταβλητή του πεδίου, συνδεδεμένη με μια θέση αποθήκευσης ανά αντικείμενο κατά την είσοδο σε οποιαδήποτε μέθοδο ή σε μπλοκ ADJUST.
Επιτρέπονται βαθμωτά, πίνακες και hashes:
class Thing {
field $scalar = 42;
field @array = qw(this is just an array);
field %hash = (species => 'Martian', planet => 'Mars');
}
Πού επιτρέπονται οι δηλώσεις πεδίων#
Μόνο απευθείας μέσα σε ένα μπλοκ class. Η field δεν είναι δηλωτικός γενικής χρήσης - δεν επιτρέπεται μέσα σε σώμα method, μπλοκ ADJUST, εμφωλευμένη sub ή σε απλό κώδικα package. Ο μεταγλωττιστής την απορρίπτει οπουδήποτε αλλού:
class C {
field $ok; # OK
method m {
field $nope; # compile error
}
}
Ένα πεδίο πρέπει να δηλωθεί πριν μπορέσει να αναφερθεί από οποιαδήποτε μέθοδο ή αρχικοποιητή στο ίδιο σώμα κλάσης.
Αρχικοποιητές πεδίων#
Αν υπάρχει = EXPR, η έκφραση εκτελείται μία φορά ανά κλήση κατασκευαστή, αφού όλα τα πεδία που δηλώθηκαν νωρίτερα στο σώμα της κλάσης έχουν αρχικοποιηθεί. Αυτό έχει σημασία όταν η προεπιλεγμένη τιμή ενός μεταγενέστερου πεδίου εξαρτάται από ένα προηγούμενο:
class WithACounter {
my $next_count = 1;
field $count = $next_count++;
}
Μέσα σε έναν αρχικοποιητή, το $self δεν υπάρχει - το αντικείμενο βρίσκεται ακόμη υπό κατασκευή. Χρησιμοποιήστε το __CLASS__ όταν ο αρχικοποιητής χρειάζεται το όνομα της κλάσης (για παράδειγμα, για να καλέσει μια μέθοδο κλάσης που οι υποκλάσεις μπορούν να παρακάμψουν):
class WithCustomField {
use constant DEFAULT_X => 10;
field $x = __CLASS__->DEFAULT_X;
}
class DifferentCustomField :isa(WithCustomField) {
sub DEFAULT_X { rand > 0.5 ? 20 : 30 }
}
Ένα στιγμιότυπο της DifferentCustomField θα δει το __CLASS__ να επιλύεται στο δικό του όνομα, οπότε ο αρχικοποιητής επιλέγει την παρακαμμένη DEFAULT_X.
Γνωρίσματα πεδίων#
Τα γνωρίσματα μετά από άνω-κάτω τελεία ελέγχουν πώς το πεδίο συμμετέχει στην κατασκευή και αν παράγονται μέθοδοι προσπέλασης για αυτό.
:param#
Λαμβάνει την τιμή του πεδίου από ένα ονομαστικό όρισμα προς τον κατασκευαστή:
field $x :param;
field $y :param(the_y_value);
By default the parameter name is the field’s name with the sigil stripped ($x → x). An explicit name in parentheses overrides that. Without a defaulting expression the parameter is required
omitting it from
->new(...)throws. With a defaulting expression the parameter is optional, and three default operators are available:=- η προεπιλογή εφαρμόζεται μόνο όταν ο καλών παρέλειψε την παράμετρο.//=- η προεπιλογή εφαρμόζεται επίσης όταν ο καλών πέρασεundef.||=- η προεπιλογή εφαρμόζεται επίσης όταν ο καλών πέρασε μια ψευδή τιμή.
class Point {
field $x :param = 0; # default if omitted
field $y :param //= 0; # default if omitted or undef
field $z :param ||= 0; # default if omitted, undef, or 0
}
:reader#
Παράγει μια μέθοδο προσπέλασης με μηδέν ορίσματα που επιστρέφει το πεδίο. Χωρίς ρητό όνομα, η μέθοδος ονομάζεται από το πεδίο (χωρίς το sigil):
field $s :reader;
# equivalent to:
field $s;
method s () { return $s }
Επιτρέπεται ρητό όνομα:
field $x :reader(get_x); # method get_x () { return $x }
Οι αναγνώστες (readers) μπορούν να εφαρμοστούν και σε πεδία πινάκων και hash· σε περιβάλλον λίστας η μέθοδος δίνει τα περιεχόμενα, ενώ σε βαθμωτό περιβάλλον τον αριθμό των στοιχείων - η συνήθης συμπεριφορά συμφραζομένων της υποκείμενης μεταβλητής:
field @users :reader;
...
scalar $instance->users; # count of users
:writer#
Παράγει μια μέθοδο setter ενός ορίσματος που εκχωρεί το όρισμά της στο πεδίο και επιστρέφει τον επικαλούμενο (invocant) (για υποστήριξη αλυσίδωσης). Το προεπιλεγμένο όνομα μεθόδου είναι το όνομα του πεδίου (χωρίς το sigil) με πρόθεμα set_:
field $s :writer;
# equivalent to:
field $s;
method set_s ($new) { $s = $new; return $self }
Επιτρέπεται ρητό όνομα:
field $x :writer(write_x); # method write_x ($new) { ... }
Το :writer λειτουργεί προς το παρόν μόνο σε βαθμωτά πεδία· η εφαρμογή του σε πεδίο πίνακα ή hash αποτελεί μοιραίο σφάλμα κατά τη μεταγλώττιση. Φτιάξτε writers για πίνακες ή hash με το χέρι.
Καθολική κατάσταση που επηρεάζει#
Καμία απευθείας. Η αποθήκευση των πεδίων ζει στο στιγμιότυπο, ενώ οι εκφράσεις αρχικοποιητών εκτελούνται στην εμβέλεια του κατασκευαστή - μπορούν να διαβάσουν οποιαδήποτε μεταβλητή ορατή στο σημείο της δήλωσης, αλλά η ίδια η field δεν επηρεάζει καμία τεκμηριωμένη ειδική μεταβλητή.
Παραδείγματα#
Ελάχιστη κλάση με ένα πεδίο, αρχικοποιημένο στο ADJUST:
use feature 'class';
no warnings 'experimental::class';
class Greeter {
field $greeting;
ADJUST {
$greeting = "Hello";
}
method say_to ($name) {
say "$greeting, $name";
}
}
Greeter->new->say_to("world"); # Hello, world
Παράμετροι κατασκευαστή μέσω :param, με συνδυασμό υποχρεωτικών και προεπιλεγμένων πεδίων:
class Point {
field $x :param; # required
field $y :param = 0; # optional, defaults to 0
method as_string { "($x, $y)" }
}
Point->new(x => 3)->as_string; # (3, 0)
Point->new(x => 3, y => 4)->as_string; # (3, 4)
Οι αυτόματα παραγόμενες μέθοδοι προσπέλασης καλύπτουν τον συνηθισμένο πάγιο κώδικα:
class Person {
field $name :param :reader;
field $age :param :reader :writer;
}
my $p = Person->new(name => "Ada", age => 36);
$p->name; # "Ada"
$p->age; # 36
$p->set_age(37); # returns $p
Πεδία πινάκων και hash με προεπιλογές:
class Bag {
field @items = ();
field %counts;
method add ($item) {
push @items, $item;
$counts{$item}++;
return $self;
}
method unique { keys %counts }
}
Αρχικοποιητής που εξαρτάται από προηγούμενο πεδίο:
class Rect {
field $w :param;
field $h :param;
field $area = $w * $h; # evaluated after $w, $h are set
}
Οριακές περιπτώσεις#
Η λεξιλογική ορατότητα έχει εμβέλεια μεθόδου, όχι αρχείου. Ένα πεδίο είναι ορατό από οποιαδήποτε
methodή μπλοκADJUSTτης ίδιας κλάσης, ανεξάρτητα από τη σειρά στο πηγαίο αρχείο. Δεν είναι ορατό από απλές δηλώσειςsubμέσα στο μπλοκ της κλάσης - μόνο απόmethod.Ανά στιγμιότυπο, όχι ανά κλάση. Δύο στιγμιότυπα της ίδιας κλάσης έχουν ανεξάρτητη αποθήκευση για κάθε πεδίο. Η εκχώρηση σε ένα στιγμιότυπο δεν επηρεάζει κάποιο άλλο. Αν θέλετε κατάσταση σε επίπεδο κλάσης, χρησιμοποιήστε μια μεταβλητή
myσε εμβέλεια αρχείου εκτός της λίστας πεδίων.Το sigil καθορίζει τον τύπο. Το
field $xείναι βαθμωτή θέση, τοfield @aθέση πίνακα, τοfield %hθέση hash. Σε αντίθεση με τα αντικείμενα βάσει hash, δεν υπάρχει τρόπος να αλλάξετε τον τύπο ενός πεδίου σε χρόνο εκτέλεσης· ο τύπος υποδοχέα της θέσης καθορίζεται από το sigil κατά τη δήλωση.Το
$selfείναι μη διαθέσιμο σε αρχικοποιητές. Το αντικείμενο δεν έχει κατασκευαστεί ακόμη όταν εκτελείται ο αρχικοποιητής. Χρησιμοποιήστε το__CLASS__για το όνομα κλάσης, και αναβάλετε στοADJUSTό,τι απαιτεί το πλήρες αντικείμενο.Η σειρά των αρχικοποιητών είναι η σειρά δήλωσης. Οι μεταγενέστεροι αρχικοποιητές μπορούν να αναφερθούν σε προηγούμενα πεδία· το αντίστροφο είναι αναφορά σε μη αρχικοποιημένη μεταβλητή.
Το
:writerσε μη-βαθμωτά πεδία είναι μοιραίο κατά τη μεταγλώττιση. Το γνώρισμα ορίζεται μόνο για βαθμωτά στην 5.42· η εφαρμογή του σε@arrή%hματαιώνει τη μεταγλώττιση της κλάσης.Το
:paramχωρίς προεπιλογή είναι υποχρεωτικό. ΗClass->new()με την παράμετρο να λείπει εγείρει εξαίρεση. Προσθέστε= EXPR,//= EXPRή||= EXPRγια να την κάνετε προαιρετική.Καμία απευθείας εξωτερική πρόσβαση. Χωρίς
:reader/:writer(ή χειρόγραφη μέθοδο) ένα πεδίο είναι μη προσπελάσιμο από έξω από την κλάση - αυτή είναι η ενθυλάκωση που παρέχει το χαρακτηριστικό class.Πειραματική προειδοποίηση. Η συντακτική ανάλυση μιας δήλωσης
fieldεκπέμπει προειδοποίησηexperimental::class, εκτός αν αυτή η κατηγορία έχει κατασταλεί· δείτε Διαφορές από το upstream.
Διαφορές από το upstream#
Πλήρως συμβατό με το upstream Perl 5.42. Το upstream σημαίνει το χαρακτηριστικό class - και συνεπώς και την field - ως πειραματικό· η pperl ακολουθεί την ίδια κατάσταση και εκπέμπει την ίδια προειδοποίηση experimental::class. Τα γνωστά upstream σφάλματα που αναφέρονται στο perlclass (segfault γύρω από κληρονομικότητα εντός αρχείου, αλληλεπιδράσεις με refaliasing και διαρρέουσα ενθυλάκωση) ισχύουν εξίσου για την pperl.
Δείτε επίσης#
class- δηλώνει την κλάση το σώμα της οποίας είναι το μόνο μέρος όπου ηfieldεπιτρέπεταιmethod- η μόνη μορφή υπορουτίνας που βλέπει μεταβλητές πεδίων με το όνομά τουςmy- συνήθης λεξιλογική δήλωση· χρησιμοποιήστε την για κατάσταση σε επίπεδο κλάσης που δεν πρέπει να είναι ανά στιγμιότυποour- δήλωση καθολική σε πακέτο· χρησιμοποιήστε την για γνήσια καθολική κατάσταση που μια κλάση θέλει να εκθέσειbless- ο τρόπος δημιουργίας αντικειμένων πριν την 5.38· ηfieldαντικαθιστά την παρακολούθηση θέσεων hash που χρειάζονταν οι κλάσεις βασισμένες στοblessref- ελέγξτε την κλάση ενός αντικειμένου σε χρόνο εκτέλεσης· εξακολουθεί να λειτουργεί σε στιγμιότυπα που παράγονται από κατασκευαστήclass