Παρεμβολή#
Οι συμβολοσειρές σε διπλά εισαγωγικά, τα here-docs, τα μοτίβα regex, η αντικατάσταση s/.../.../ και η qq// κάνουν όλα παρεμβολή: αναπτύσσουν μεταβλητές και ορισμένες ακολουθίες διαφυγής επιτόπου. Οι συμβολοσειρές σε μονά εισαγωγικά, η q// και το αριστερό μοτίβο της tr/.../.../ δεν το κάνουν. Η γνώση ποιες κατασκευές κάνουν παρεμβολή και ακριβώς ποιες μορφές αναπτύσσονται είναι μία από τις πιο χρήσιμες γνώσεις Perl.
my $name = "Alice";
my @nums = (1, 2, 3);
"hello, $name" # "hello, Alice"
'hello, $name' # 'hello, $name' - single quotes don't interpolate
"@nums in a string" # "1 2 3 in a string"
"\$name is $name" # "$name is Alice"
Τι παρεμβάλλεται#
Μέσα σε "" (και τα άλλα περιβάλλοντα τύπου διπλών εισαγωγικών), η Perl αναπτύσσει ακριβώς δύο μορφές μεταβλητής:
$name # scalar - the simple form
@list # array - joined by $" (one space by default)
Επιπλέον οι μορφές subscript με αγκύλες και άγκιστρα που συνθέτονται πάνω σε αυτές:
$arr[0] # one element of @arr
$h{key} # one value from %h
$ref->[0] # via array ref
$ref->{key} # via hash ref
@arr[1, 2] # array slice
@h{qw(a b)} # hash slice
Σημειώστε ότι ολόκληρα hashes δεν παρεμβάλλονται:
"hash is %h" # "hash is %h" - literal '%' is fine, '%h' is NOT magical
Αν θέλετε ένα hash εκτυπωμένο σε συμβολοσειρά, μορφοποιήστε το ρητά με Data::Dumper ή χειροκίνητο join.
Τι δεν παρεμβάλλεται#
&sub # function calls don't interpolate
sub_with_args($x) # neither do calls with arguments
$h->method # method calls don't interpolate
$obj->{a} + 1 # arithmetic doesn't interpolate
$arr[0+1] # this DOES interpolate as $arr[0+1] - subscripts allow expressions
"\u\L$name" # case-modifying escapes - these DO interpolate
"\x{2603}" # numeric escapes - DO interpolate (a snowman)
Ο πρακτικός κανόνας: οι μεταβλητές και τα subscripts τους παρεμβάλλονται· οι κλήσεις συναρτήσεων/μεθόδων και οι αριθμητικές πράξεις πάνω σε αυτές δεν παρεμβάλλονται. Όταν θέλετε παρεμβολή μιας έκφρασης, δείτε τις κατασκευές @{[ ... ]} και ${\ ... } παρακάτω.
Οι αγκύλες ${name}#
Οι αγκύλες γύρω από ένα όνομα μεταβλητής αποσαφηνίζουν πού τελειώνει το όνομα:
my $who = "Larry";
"${who}speak" # "Larryspeak"
"$whospeak" # "" with warning: $whospeak is uninitialised
"${who}::sub" # "Larry::sub"
"$who::sub" # the variable $who::sub from package who - bug
Χωρίς τις αγκύλες, η Perl είναι άπληστη: η $whospeak διαβάζεται ως ένα αναγνωριστικό, η $who::sub διαβάζεται ως πλήρως κατονομασμένο όνομα. Οι αγκύλες αναγκάζουν τον αναλυτή να σταματήσει στο }.
Αυτή δεν είναι η ίδια μορφή αγκυλών με ένα subscript hash:
"$h{key}" # hash element - what most people mean
"${h}{key}" # hash element in a different parse path - same result
"${h{key}}" # also the same
"${\(\$h{key})}" # the absurd "interpolate an expression" form
Οι αγκύλες ${name} χρησιμοποιούνται κυρίως στην περίπτωση αποσαφήνισης (όνομα ακολουθούμενο από αλφαριθμητικούς χαρακτήρες που αλλιώς θα καταναλώνονταν), όχι για πρόσβαση σε hash.
Οι μορφές αποαναφοράς με αγκύλες @{...} και ${...}#
Όταν θέλετε να αποαναφέρετε κάτι μέσα σε συμβολοσειρά, η μορφή με αγκύλες επιτρέπει η έκφραση αποαναφοράς να είναι αυθαίρετη:
my $config = { users => ['Alice', 'Bob'] };
"users: @{ $config->{users} }" # "users: Alice Bob"
"users: $config->{users}" # "users: ARRAY(0x...)" - wrong; whole arrayref stringified
"users: @$config->{users}" # parse error / wrong
The @{ EXPR } form deref’s EXPR as an array. The braces are required because the deref target is an expression, not a plain variable. @$config->{users} doesn’t parse the way intended
@$configwould deref$configas an array, and->{users}is a hash-element access on what’s left.
Το ίδιο ισχύει για ${ EXPR } (βαθμωτή αποαναφορά) και %{ EXPR } (αποαναφορά hash, που επιστρέφει επίπεδη λίστα, σπάνια χρήσιμη στην παρεμβολή).
@{[ expr ]} - παρεμβολή οποιασδήποτε έκφρασης λίστας#
Για παρεμβολή του αποτελέσματος μιας αυθαίρετης έκφρασης, τυλίξτε την σε @{[ ... ]}:
my $name = "World";
print "hello, @{[ uc $name ]}!\n"; # "hello, WORLD!"
print "found @{[ scalar @hits ]} matches\n"; # interpolate a count
print "users: @{[ join ', ', @users ]}\n"; # interpolate a join
Ο μηχανισμός: η [ ... ] κατασκευάζει μια ανώνυμη αναφορά πίνακα με περιεχόμενα την τιμή της έκφρασης σε περιβάλλον λίστας· η @{ ... } στη συνέχεια αποαναφέρει αυτή την αναφορά πίνακα σε λίστα, η οποία παρεμβάλλεται όπως μια λίστα (ενωμένη με $").
Αυτός είναι ο κανονικός τρόπος αντιμετώπισης του «θέλω κλήση συνάρτησης μέσα σε συμβολοσειρά με διπλά εισαγωγικά». Η εναλλακτική είναι η συνένωση:
print "hello, " . uc($name) . "!\n"; # equivalent
Η μορφή @{[ ... ]} είναι πιο πυκνή όταν υπάρχουν πολλαπλές παρεμβολές· η συνένωση είναι πιο σαφής όταν υπάρχει μόνο μία. Σε πρότυπα με πολλά πεδία, η printf ή η sprintf είναι συνήθως ακόμα πιο σαφής:
printf "found %d matches\n", scalar @hits;
Χρησιμοποιήστε @{[ ... ]} όταν θέλετε πραγματικά μια έκφραση Perl στη μέση μιας συμβολοσειράς και οι εναλλακτικές είναι πιο άσχημες.
${\ expr } - παρεμβολή βαθμωτής έκφρασης#
Το βαθμωτό αντίστοιχο της @{[ ... ]}:
print "answer: ${\ 6 * 7 }\n"; # "answer: 42"
print "ts: ${\ scalar localtime }\n"; # "ts: Mon Apr 27 ..."
Η \ EXPR δημιουργεί αναφορά στη βαθμωτή τιμή της EXPR· η ${ ... } την αποαναφέρει. Το αποτέλεσμα είναι μία τιμή, παρεμβαλλόμενη ως βαθμωτό.
Στις περισσότερες περιπτώσεις η μορφή @{[ ... ]} είναι πιο ομοιόμορφη - λειτουργεί τόσο σε βαθμωτό όσο και σε περιβάλλον λίστας. Η ${\ ... } είναι περιστασιακά πιο σαφής όταν θέλετε συγκεκριμένα βαθμωτό περιβάλλον:
"got @{[ items() ]} items" # items() called in LIST context
"got ${\ items() } items" # items() called in SCALAR context
Αμφισημία subscript hash σε μοτίβα#
Μέσα σε μοτίβο regex (που είναι τύπου διπλών εισαγωγικών), ο αναλυτής πρέπει να μαντέψει αν η $foo[bar] σημαίνει «παρεμβολή $foo[bar] (ένα στοιχείο της @foo)» ή «παρεμβολή $foo και στη συνέχεια αντιστοίχιση κλάσης χαρακτήρων [bar]»:
my @foo = ('hi');
$x =~ /$foo[abc]/ # @foo exists - parsed as $foo[abc] (one element)
$x =~ /$foo[abc]/ # @foo doesn't exist - parsed as $foo + char class
Η αποσαφήνιση γίνεται με τη μορφή αγκυλών:
$x =~ /${foo}[abc]/ # $foo + character class [abc]
$x =~ /$foo[5]/ # element 5 of @foo
$x =~ /\Q$foo\E[abc]/ # $foo (literal) + character class
Ο \Q...\E απενεργοποιεί την ερμηνεία μετα-χαρακτήρων εντός της εμβέλειάς του, κάτι που είναι η πιο καθαρή λύση όταν η μεταβλητή είναι είσοδος χρήστη.
Heredocs#
Τα heredocs είναι τύπου διπλών εισαγωγικών εκτός αν ο δείκτης είναι σε μονά εισαγωγικά:
my $msg = <<EOM;
Hello, $name!
The hash is %h.
EOM
# "Hello, Alice!\nThe hash is %h.\n" - $name interpolated, %h literal
my $msg = <<'EOM';
Hello, $name!
EOM
# "Hello, $name!\n" - single-quoted marker disables interpolation
Τα εσοχοποιημένα heredocs (Perl 5.26+) αγνοούν τα αρχικά κενά μέχρι τη μικρότερη ακολουθία σε οποιαδήποτε γραμμή:
my $msg = <<~EOM;
Hello, $name!
EOM
# "Hello, Alice!\n" - leading " " stripped from every line
Η μορφή ~ προτιμάται σε σύγχρονο κώδικα· η μη εσοχοποιημένη μορφή είναι άσχημη μέσα σε βρόχους και σώματα μεθόδων.
Πραγματικό παράδειγμα: κατασκευή HTML με ασφάλεια#
my @items = ('Apples', 'Bananas', 'Cherries');
my $html = <<~HTML;
<ul>
@{[ map { " <li>$_</li>" } @items ]}
</ul>
HTML
Η map επιστρέφει μια λίστα συμβολοσειρών <li>...</li>· η @{[ ... ]} τις παρεμβάλλει· η σιωπηρή $" είναι ένα κενό, δίνοντας:
<ul>
<li>Apples</li> <li>Bananas</li> <li>Cherries</li>
</ul>
Για αλλαγές γραμμής μεταξύ στοιχείων, ορίστε τοπικά τη $":
my $html = do {
local $" = "\n";
<<~HTML;
<ul>
@{[ map { " <li>$_</li>" } @items ]}
</ul>
HTML
};
Ή ενώστε ρητά:
my $li = join "\n", map { " <li>$_</li>" } @items;
my $html = "<ul>\n$li\n</ul>\n";
Η ρητή join είναι συνήθως πιο σαφής για μη τετριμμένα πρότυπα. Η μορφή @{[ ... ]} κερδίζει τη θέση της όταν το πρότυπο είναι κυρίως κυριολεκτικό κείμενο με έναν ή δύο ενσωματωμένους υπολογισμούς.
Τι ελέγχει η ειδική μεταβλητή $"#
Ο διαχωριστής λίστας στην παρεμβολή:
my @x = (1, 2, 3);
print "x = @x\n"; # "x = 1 2 3" - default $" is " "
local $" = ", ";
print "x = @x\n"; # "x = 1, 2, 3"
local $" = "\n ";
print "items:\n @x\n"; # "items:\n 1\n 2\n 3"
Η $" είναι ο κανονικός τρόπος ελέγχου του πώς παρεμβάλλονται οι πίνακες χωρίς αναγραφή της συμβολοσειράς. Δείτε filehandle and printing state για την οικογένεια μεταβλητών διαχωριστή.
Δείτε επίσης#
Scalars, Arrays, Hashes - οι μορφές που αναπτύσσει η παρεμβολή.
References - η μορφή αποαναφοράς
@{ EXPR }και τι κάνει η\στην${\ ... }.$"- ο διαχωριστής λίστας για παρεμβολή πίνακα.$,,$\,$/- οι σχετικές μεταβλητές διαχωριστή γιαprintκαι είσοδο.-
the explicit format-string alternative when the template is mostly punctuation.
qq,q,qw- οι τελεστές τύπου εισαγωγικών με προσαρμοσμένους οριοθέτες.