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

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');
}

Αρχικοποιητές πεδίων#

Αν υπάρχει = 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 ($xx). 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 που χρειάζονταν οι κλάσεις βασισμένες στο bless

  • ref - ελέγξτε την κλάση ενός αντικειμένου σε χρόνο εκτέλεσης· εξακολουθεί να λειτουργεί σε στιγμιότυπα που παράγονται από κατασκευαστή class