Filehandles με tie#

Ένα filehandle με tie δρομολογεί εκ νέου το I/O όπως ένα βαθμωτό με tie δρομολογεί εκ νέου τις αναγνώσεις και τις εγγραφές. Εκτυπώστε σε αυτό και τρέχει το δικό σας PRINT· διαβάστε μια γραμμή και τρέχει το δικό σας READLINE. Οι κλασικές χρήσεις είναι η ανακατεύθυνση της εξόδου κάπου ασυνήθιστα (σε μια συμβολοσειρά, μέσα από δίκτυο, μέσα από ένα φίλτρο) και η ενσωμάτωση της Perl σε ένα πρόγραμμα-ξενιστή που χρειάζεται ειδικό χειρισμό των STDOUT και STDERR.

Η διεπαφή είναι μεγαλύτερη από τις άλλες αλλά κατά κύριο λόγο προαιρετική: υλοποιείτε μόνο τις λειτουργίες που θα λάβει στην πραγματικότητα το handle. Το πλήρες μενού βρίσκεται στη σελίδα αναφοράς του tie· αυτό το κεφάλαιο φτιάχνει μια κλάση και εξηγεί τα hooks και τον χρονισμό τους.

Μια πλήρης κλάση#

Ένα handle μόνο για εγγραφή που συγκεντρώνει σε μια συμβολοσειρά οτιδήποτε εκτυπώνεται σε αυτό:

use v5.36;

package Collector {
    sub TIEHANDLE { my $class = shift; my $buf = ''; return bless \$buf, $class }
    sub PRINT     { my $self = shift; $$self .= join($, // '', @_); return 1 }
    sub PRINTF    { my $self = shift; my $fmt = shift; $$self .= sprintf($fmt, @_); return 1 }
    sub buffer    { my $self = shift; return $$self }
}

tie *OUT, 'Collector';
print OUT "hello ";
print OUT "world\n";
printf OUT "%d items\n", 3;
my $obj = tied *OUT;
print $obj->buffer;
# hello world
# 3 items

Το αντικείμενο είναι μια blessed αναφορά βαθμωτού που κρατά το συσσωρευμένο κείμενο. Η επιπλέον μέθοδος buffer προσεγγίζεται μέσω του tied, όχι μέσω κάποιας λειτουργίας I/O - αυτός είναι ο τυπικός τρόπος με τον οποίο μια κλάση tie εκθέτει λειτουργίες χωρίς σύνταξη filehandle.

Δέσιμο με tie του glob, όχι του βαθμωτού#

Το πρώτο όρισμα στο tie για ένα handle πρέπει να είναι ένα glob - ξεκινά με αστερίσκο:

  • Για να δέσετε με tie ένα κατονομασμένο handle: tie *OUT, 'Collector'.

  • Για να δέσετε με tie ένα handle που κρατείται σε ένα βαθμωτό $fh: tie *$fh, 'Collector'. Το να γράψετε tie $fh, ... δένει το βαθμωτό $fh, όχι το handle μέσα του - ένα συνηθισμένο και μπερδευτικό λάθος.

Το συμβόλαιο των μεθόδων#

TIEHANDLE classname, LIST

Ο κατασκευαστής· επιστρέφει μια blessed αναφορά οποιουδήποτε είδους. Μπορεί να κρατά όποια εσωτερική κατάσταση χρειάζεται το handle.

PRINT this, LIST

Στηρίζει τα print και say. Λαμβάνει την εκτυπωμένη λίστα. Τιμήστε το $, (τον διαχωριστή πεδίων εξόδου) ανάμεσα στα στοιχεία και το $\ (τον τερματιστή εγγραφής εξόδου) στο τέλος αν θέλετε πλήρη πιστότητα - το print δεν τα εισάγει για εσάς.

PRINTF this, format, LIST

Στηρίζει το printf. Λαμβάνει τη συμβολοσειρά μορφής και τα ορίσματα· περάστε τα εσείς οι ίδιοι μέσα από το sprintf.

WRITE this, scalar, length, offset

Στηρίζει το syswrite - την ακατέργαστη, προσανατολισμένη σε ενταμιευτή εγγραφή, διακριτή από το PRINT.

READLINE this

Στηρίζει τα <$fh> και readline. Σε βαθμωτό περιβάλλον επιστρέψτε την επόμενη γραμμή ή undef στο τέλος της εισόδου· σε περιβάλλον λίστας επιστρέψτε όλες τις υπόλοιπες γραμμές ή μια κενή λίστα. Οι επιστρεφόμενες συμβολοσειρές πρέπει να περιλαμβάνουν τον διαχωριστή εγγραφής εισόδου $/, ώστε να ταιριάζουν με ό,τι σας δίνει ένα πραγματικό handle.

READ this, scalar, length, offset / GETC this

Στηρίζουν τα read / sysread και getc αντίστοιχα.

OPEN, CLOSE, EOF, BINMODE, FILENO, SEEK, TELL

Στηρίζουν τις αντίστοιχες ενσωματωμένες όταν χρησιμοποιούνται πάνω στο handle. Υλοποιήστε εκείνες που έχουν νόημα για τον υποκείμενο αποθηκευτικό χώρο σας και αφήστε τις υπόλοιπες απ” έξω.

DESTROY this / UNTIE this

Προαιρετικός καθαρισμός, ταυτόσημος σε ρόλο με τους άλλους τύπους tie. Μια κλάση handle συχνά κλείνει εδώ τον υποκείμενο πόρο της.

Χρονισμός κλήσεων#

  • print FH @list και say FH @listPRINT. Το say επιπλέον εντοπίζει τοπικά το $\ σε "\n" γύρω από την κλήση, οπότε ένα PRINT που τιμά το $\ χειρίζεται το say χωρίς ειδική περίπτωση.

  • printf FH $fmt, @argsPRINTF.

  • syswrite FH, $buf, $len, $offWRITE.

  • <FH> / readline FHREADLINE, στο περιβάλλον που το περικλείει.

  • read/sysreadREAD· getc FHGETC.

  • close FH, eof FH, binmode FH, seek, tell, fileno, open FH, ... → το αντίστοιχο hook με κεφαλαία όταν είναι ορισμένο.

Μια σημείωση για το STDERR: όταν το STDERR είναι δεμένο με tie, το PRINT του είναι αυτό που εκδίδει τις προειδοποιήσεις και τα μηνύματα σφαλμάτων. Ο χρόνος εκτέλεσης απενεργοποιεί το tie για τη διάρκεια εκείνης της κλήσης, οπότε μπορείτε να καλέσετε warn μέσα από το PRINT χωρίς να πυροδοτήσετε άπειρη αναδρομή.

Ελάχιστη βιώσιμη κλάση#

Δεν υπάρχει καμία μεμονωμένη υποχρεωτική μέθοδος πέρα από το TIEHANDLE - υλοποιείτε όποιες λειτουργίες θα λάβει το handle. Ένα handle μόνο για έξοδο χρειάζεται το TIEHANDLE συν το PRINT (και συνήθως το PRINTF). Ένα handle μόνο για είσοδο χρειάζεται το TIEHANDLE συν το READLINE (και ίσως το GETC / READ). Οι λειτουργίες των οποίων το hook λείπει πεθαίνουν στο σημείο χρήσης, οπότε ορίστε ακριβώς το σύνολο που χρησιμοποιούν οι καλούντές σας.

Ο εύκολος τρόπος: κληρονομήστε από το Tie::StdHandle#

Το Tie::StdHandle (που συνοδεύει το Tie::Handle) δένει ένα handle πάνω σε ένα πραγματικό υποκείμενο: το OPEN του ανοίγει ένα πραγματικό αρχείο και τα hooks I/O προωθούν σε αυτό. Κληρονομήστε από αυτό και υπερκαλύψτε μόνο τις λειτουργίες που θέλετε να υποκλέψετε:

package Doubler {
    use Tie::StdHandle;
    our @ISA = ('Tie::StdHandle');
    sub READLINE {
        my $self = shift;
        my $line = $self->SUPER::READLINE;
        return defined $line ? $line . $line : undef;   # echo each line twice
    }
}

my $data = "a\nb\n";
tie *DUP, 'Doubler';
tied(*DUP)->OPEN('<', \$data);
print while defined($_ = <DUP>);
# a
# a
# b
# b

Το READLINE καλεί προς τα πάνω τη βασική κλάση για την πραγματική επόμενη γραμμή, και έπειτα τη διπλασιάζει· κάθε άλλη λειτουργία ρέει μέσα από το Tie::StdHandle αμετάβλητη. Το Tie::Handle (ο γονέας) είναι η αφηρημένη βάση που τεκμηριώνει τη διεπαφή και παρέχει ένα προεπιλεγμένο PRINT/PRINTF με όρους του WRITE· το Tie::StdHandle είναι η συγκεκριμένη, έτοιμη προς χρήση.

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

  • tie - η ενσωματωμένη και το πλήρες μενού μεθόδων handle

  • tied - ο μόνος τρόπος να προσεγγίσετε τις μη-I/O μεθόδους μιας κλάσης handle, όπως το buffer παραπάνω

  • print και printf - οι ενσωματωμένες πίσω από τα PRINT και PRINTF

  • readline - η σελίδα του τεκμηριώνει το συμβόλαιο επιστροφής βαθμωτού/λίστας που πρέπει να τιμά το READLINE

  • Βαθμωτά με tie - ο απλούστερος τύπος tie, ένα καλό προθέρμασμα για τη διεπαφή handle

  • Tie::Handle - το άρθρωμα της βασικής κλάσης· το Tie::StdHandle είναι η συγκεκριμένη εκδοχή