Από Lua σε Perl#
Ξέρετε Lua. Χτίζετε ένα table χωρίς να το σκέφτεστε, φτάνετε στο setmetatable για να πάρετε αντικείμενα και τελεστές, και το for k, v in pairs(t) είναι μυϊκή μνήμη. Αυτός ο οδηγός αντιστοιχίζει καθεμία από αυτές τις συνήθειες στην Perl, ώστε να γίνετε παραγωγικοί στο pperl μέσα σε ένα απόγευμα αντί να ξαναμάθετε προγραμματισμό από το μηδέν.
Δύο σοκ φτάνουν μέσα στα πρώτα πέντε λεπτά, οπότε γνωρίστε τα τώρα:
Ο ένας τύπος table της Lua γίνεται δύο τύποι στην Perl. Η Lua έχει ένα μοναδικό σύνολο, το table, που το χρησιμοποιείτε και ως πίνακα (
{1, 2, 3}) και ως αντιστοίχιση ({k = "v"}). Η Perl το χωρίζει σε δύο διακριτά πράγματα: έναν διατεταγμένο@arrayμε ακέραια κλειδιά και ένα%hashμε κλειδιά συμβολοσειρών. Η απόφαση «είναι αυτό λίστα ή αναζήτηση;» εξαρχής είναι η κεντρική νέα συνήθεια, και οι ενότητες Πίνακες και Hashes δεν αφορούν τίποτε άλλο.Οι μεταβλητές φορούν sigils. Τα ονόματα της Lua είναι σκέτα:
x,t,f. Στην Perl ένα βαθμωτό είναι$x, ένας πίνακας είναι@x, ένα hash είναι%x. Το sigil είναι μέρος του πώς διαβάζετε τη μεταβλητή, όχι απλώς διακόσμηση. Αυτή είναι η μεγαλύτερη επιφανειακή διαφορά από τη Lua, και η πρώτη ενότητα δεν αφορά τίποτε άλλο.
Every example here runs on pperl, a Rust reimplementation of Perl 5.42. Each Perl snippet was executed on pperl; the # ... comments show its real output. Start your scripts with:
use v5.42;
Αυτή η μία γραμμή ενεργοποιεί το strict (κάθε μεταβλητή πρέπει να δηλώνεται με my, η θεραπεία για τις επιρρεπείς σε ατυχήματα σιωπηρές καθολικές της Lua), τα warnings, την ενσωματωμένη say (ένα print με τελικό χαρακτήρα νέας γραμμής, όπως το print της Lua), τις υπογραφές υπορουτινών, και το σύγχρονο σύνολο χαρακτηριστικών που χρησιμοποιείται σε όλον αυτόν τον οδηγό.
Πώς να το διαβάσετε αυτό#
Μεταβλητές και sigils - η μετάβαση
$/@/%, και τοlocal xπου γίνεταιmy $x.Συμβολοσειρές - παρεμβολή, και η συνένωση
..που γίνεται..Αριθμοί - ένας επιφανειακός τύπος, διαίρεση κινητής υποδιαστολής.
Πίνακες και λίστες - το μισό από το table σας, 0-based όχι 1-based.
Hashes - το άλλο μισό από το table σας.
Περιβάλλον - η έννοια για την οποία η Lua δεν έχει λέξη. Διαβάστε αυτήν.
Αλήθεια - τι μετράει ως ψευδές, και διαφέρει έντονα από τη Lua.
Ροή ελέγχου -
if, βρόχοι, οι μεταθεματικές μορφές.Υπορουτίνες - το
functionγίνεταιsub· πραγματικά closures.Αναφορές - εμφωλευμένα δεδομένα και closures.
Κανονικές εκφράσεις - πραγματικό regex, όχι μοτίβα της Lua.
I/O αρχείων και ροών -
open, αναγνώσεις γραμμών, slurp.Αρθρώματα και πακέτα - το
requireγίνεταιuse.Αντικείμενα - τα metatables γίνονται η σύγχρονη σύνταξη
class.Χειρισμός σφαλμάτων - το
pcallγίνεταιevalήtry/catch.Ιδιώματα - τα καθημερινά μονόγραμμα.
Παγίδες ερχόμενοι από τη Lua - σαρώστε τες πριν γράψετε.
Μεταβλητές και sigils#
Στη Lua ένα όνομα απλώς ονοματίζει μια τιμή, όποιο κι αν είναι το σχήμα της. Στην Perl το sigil σας λέει το σχήμα: $ για μία τιμή, @ για μια διατεταγμένη λίστα, % για μια αντιστοίχιση κλειδιού/τιμής. Το my δηλώνει μια μεταβλητή με λεξιλογική εμβέλεια, τον ακριβή ρόλο του local της Lua. Εκεί που η Lua αφήνει μια σκέτη ανάθεση να δημιουργήσει σιωπηλά μια καθολική, το use v5.42 το μετατρέπει σε σφάλμα μεταγλώττισης: κάθε μεταβλητή είναι my εκτός αν πείτε διαφορετικά.
local name = "Ada"
local langs = {"Lua", "Perl"}
local ages = {Ada = 36, Linus = 56}
use v5.42;
my $name = "Ada";
my @langs = ("Lua", "Perl");
my %ages = (Ada => 36, Linus => 56);
say $name; # Ada
say $langs[0]; # Lua
say $ages{Ada}; # 36
Η παγίδα: όταν φτάνετε μέσα σε ένα σύνολο για ένα στοιχείο, το sigil ακολουθεί την τιμή που παίρνετε πίσω, όχι τον περιέκτη. Ένα μεμονωμένο στοιχείο του @langs είναι βαθμωτό, οπότε είναι $langs[0], όχι @langs[0]· μία τιμή από το %ages είναι $ages{Ada}. Η μορφή @/% είναι όλη η συλλογή· η μορφή $ είναι ένα κομμάτι της. Στη Lua το όνομα table t δεν αλλάζει ποτέ είτε γράφετε t, t[1], ή t.key· στην Perl το αρχικό σημάδι αλλάζει ανάλογα με το τι προσπελαύνετε.
Συμβολοσειρές#
Τα διπλά εισαγωγικά παρεμβάλλουν μεταβλητές, τα μονά όχι. Δεν χρειάζεται κανένα αντανακλαστικό string.format για τη συνηθισμένη περίπτωση, επειδή η προεπιλεγμένη συμβολοσειρά ήδη παρεμβάλλει. Η μεγάλη αλλαγή: η συνένωση είναι ., εκεί που η Lua χρησιμοποιεί ...
local name = "Ada"
local greeting = "Hello, " .. name
local shout = string.rep("AB", 3)
use v5.42;
my $name = "Ada";
my $greeting = "Hello, $name"; # Hello, Ada
my $literal = 'Hello, $name'; # Hello, $name (no interpolation)
my $joined = "AB" . "CD"; # ABCD
my $shout = "AB" x 3; # ABABAB
Η παγίδα: ο τελεστής συνένωσης .. της Lua δεν υπάρχει στην Perl· η μονή τελεία . ενώνει συμβολοσειρές και ο τελεστής x τις επαναλαμβάνει (το string.rep της Lua). Τα στοιχεία πίνακα και οι τιμές hash παρεμβάλλονται και μέσα σε διπλά εισαγωγικά, οπότε το "First: $langs[0]" δουλεύει όπως είναι γραμμένο, που εξαλείφει το μεγαλύτερο μέρος της αλυσίδωσης με .. στην οποία καταφεύγει ένας προγραμματιστής της Lua.
Αριθμοί#
Η Perl έχει έναν αριθμητικό τύπο στην επιφάνεια· δεν επιλέγετε μεταξύ ακεραίου και float, όπως ακριβώς η Lua 5.3+ παρουσιάζει έναν μοναδικό number στον περισσότερο κώδικα. Η διαίρεση πάντα παράγει έναν αριθμό κινητής υποδιαστολής.
print(7 / 2) -- 3.5
print(math.floor(7 / 2)) -- 3
print(2 ^ 10) -- 1024.0
print(10 % 3) -- 1
use v5.42;
say 7 / 2; # 3.5
say int(7 / 2); # 3
say 2 ** 10; # 1024
say 10 % 3; # 1
Η παγίδα: οι τελεστές σύγκρισης και ισότητας έρχονται σε δύο οικογένειες, και επιλέγετε με βάση τον τύπο των τελεστέων, όχι των μεταβλητών. Οι αριθμοί χρησιμοποιούν ==, !=, <, >, <=>· οι συμβολοσειρές χρησιμοποιούν eq, ne, lt, gt, cmp. Το "10" == "10.0" είναι αληθές (αριθμητικά), αλλά το "10" eq "10.0" είναι ψευδές (συμβολοσειρά). Η Lua έχει μόνο το == και δεν εξαναγκάζει τίποτε πέρα από τη γραμμή συμβολοσειράς/αριθμού· η Perl αντ” αυτού ζητάει από εσάς να επιλέξετε τη σύγκριση, και η χρήση == σε συμβολοσειρές (ή eq σε αριθμούς) είναι ένα συχνό σιωπηλό σφάλμα.
Πίνακες και λίστες#
Εδώ είναι το μισό του μεγάλου διαχωρισμού του table. Μια ακολουθία της Lua ({10, 20, 30}, το table χρησιμοποιούμενο ως πίνακας) γίνεται ένας @array της Perl. Η πρώτη και πιο εμφανής διαφορά: οι πίνακες της Perl είναι 0-based, εκεί που οι πίνακες της Lua συμβατικά ξεκινούν από τον δείκτη 1.
local t = {"x", "y", "z"}
print(t[1]) -- x (Lua: first element is index 1)
print(t[3]) -- z
print(#t) -- 3 (length)
use v5.42;
my @t = ("x", "y", "z");
say $t[0]; # x (Perl: first element is index 0)
say $t[2]; # z
say $t[-1]; # z (negative indices count from the end)
say scalar @t; # 3 (length; @t in scalar context is its size)
Οι μεταλλάκτες έχουν μετονομαστεί αλλά είναι οικείοι. Τα table.insert/table.remove γίνονται push/pop/shift/unshift:
use v5.42;
my @nums = (10, 20, 30);
push @nums, 40; # add to the end
my $last = pop @nums; # 40, removed from the end
say scalar @nums; # 3
say "@nums[0,1]"; # 10 20 (a slice)
Η Lua καταφεύγει σε ρητούς βρόχους for i = 1, #t do ... end για να μετασχηματίσει ή να φιλτράρει· η Perl έχει map (μετασχηματισμός) και grep (φιλτράρισμα), με το $_ ως το τρέχον στοιχείο:
use v5.42;
my @nums = (1, 2, 3, 4, 5);
my @squares = map { $_ * $_ } @nums; # 1 4 9 16 25
my @evens = grep { $_ % 2 == 0 } @nums; # 2 4
my @desc = sort { $b <=> $a } @nums; # 5 4 3 2 1
Η παγίδα: πέρα από την ευρετηρίαση 0-based, το #t δεν έχει μία μόνο γραφή στην Perl - χρησιμοποιείτε scalar @a για το μήκος ενός πίνακα και keys %h για ενός hash. Και το sort συγκρίνει ως συμβολοσειρές από προεπιλογή, οπότε το sort (10, 9, 100) δίνει 10 100 9. Για αριθμούς πρέπει να περάσετε έναν συγκριτή: sort { $a <=> $b } @nums. Τα $a και $b είναι τα δύο στοιχεία που συγκρίνονται, και το <=> είναι ο αριθμητικός τρίτιμος τελεστής (το cmp είναι το αδελφάκι του για συμβολοσειρές).
Hashes#
Εδώ είναι το άλλο μισό του διαχωρισμού του table. Ένα table της Lua χρησιμοποιούμενο ως αντιστοίχιση ({name = "Ada", age = 36}, ή t["key"]) γίνεται ένα %hash της Perl. Δηλώνεται με %, και προσπελαύνεται μία τιμή τη φορά με $h{key}.
local h = {apple = 3, pear = 5, plum = 2}
print(h.apple) -- 3
print(h["pear"]) -- 5
h.plum = nil -- delete a key
for k, v in pairs(h) do
print(k, v)
end
use v5.42;
my %h = (apple => 3, pear => 5, plum => 2);
say $h{apple}; # 3
say join ",", sort keys %h; # apple,pear,plum
say exists $h{pear} ? "yes" : "no"; # yes
delete $h{plum};
for my $k (sort keys %h) {
say "$k => $h{$k}"; # apple => 3 ... pear => 5
}
Η παγίδα: η Lua συγχωνεύει τον πίνακα και την αντιστοίχιση σε ένα table και κρατάει και ένα μέρος πίνακα και ένα μέρος hash μέσα του· η Perl τα κρατάει αυστηρά χωριστά, οπότε αποφασίζετε εξαρχής αν ένα πράγμα είναι ένας @array (ακέραιες θέσεις, διατεταγμένος) ή ένα %hash (κλειδιά συμβολοσειρών, αδιάτακτο). Ο έλεγχος μέλους είναι exists $h{key}, το αντίστοιχο του ελέγχου h[k] ~= nil της Lua, και το παχύ κόμμα => είναι ο ιδιωματικός διαχωριστής κλειδιού/τιμής που βάζει αυτόματα εισαγωγικά στο bareword στα αριστερά του (οπότε το apple => 3 δεν χρειάζεται εισαγωγικά). Ένα hash δεν έχει σειρά, οπότε επαναλάβετε με sort keys %h όταν θέλετε μια σταθερή· το pairs της Lua είναι αδιάτακτο για τον ίδιο λόγο.
Περιβάλλον#
Αυτό είναι το κεφάλαιο που πρέπει να διαβάσετε δύο φορές. Η Lua δεν έχει γενικό αντίστοιχο, και σχεδόν κάθε ιστορία «η Perl είναι παράξενη» ανάγεται σε αυτό. Αλλά η Lua όντως σας δίνει τη μία γέφυρα που το κάνει να βγάζει νόημα: τις πολλαπλές τιμές επιστροφής.
Στη Lua, το local a, b = f() απλώνει τις πολλές τιμές επιστροφής μιας συνάρτησης σε πολλές μεταβλητές, και το #t ή το select("#", ...) συμπτύσσει μια λίστα σε ένα πλήθος. Η Perl γενικεύει αυτή την ιδέα σε μια ιδιότητα κάθε έκφρασης. Κάθε έκφραση τρέχει είτε σε περιβάλλον λίστας είτε σε βαθμωτό περιβάλλον, που καθορίζεται από το πού εμφανίζεται. Ο ίδιος πίνακας συμπεριφέρεται διαφορετικά σε καθένα: ανατεθειμένος σε ένα βαθμωτό δίνει το μήκος του, ανατεθειμένος σε μια λίστα (μεταβλητές σε παρενθέσεις) αντιγράφει στοιχεία.
use v5.42;
my @list = (10, 20, 30);
my $count = @list; # scalar context -> 3 (the length)
say $count; # 3
my ($first) = @list; # list context -> first element copied
say $first; # 10
my ($a, $b) = @list; # 10 and 20
say "$a $b"; # 10 20
Οι παρενθέσεις στα αριστερά είναι όλη η διαφορά. Το my $x = @list ρωτάει «πόσα;» και παίρνει 3. Το my ($x) = @list ρωτάει «δώσε μου τα στοιχεία» και παίρνει 10. Η μορφή λίστας my ($a, $b) = @list είναι ακριβώς το local a, b = ... της Lua - η γέφυρα που ήδη ξέρετε.
Μια υπορουτίνα που επιστρέφει πολλές τιμές είναι το ίδιο με μια συνάρτηση της Lua με πολλές τιμές return· το περιβάλλον του καλούντος αποφασίζει τι επιστρέφεται:
use v5.42;
sub minmax (@nums) {
my @s = sort { $a <=> $b } @nums;
return ($s[0], $s[-1]);
}
my ($lo, $hi) = minmax(4, 1, 9, 2);
say "$lo $hi"; # 1 9
Μια sub μπορεί ακόμη και να ρωτήσει σε ποιο περιβάλλον κλήθηκε, με wantarray, και να απαντήσει διαφορετικά - κάτι που οι συναρτήσεις της Lua δεν μπορούν να κάνουν:
use v5.42;
sub items {
return wantarray ? (1, 2, 3) : "three items";
}
my @got = items(); # list context
my $msg = items(); # scalar context
say "@got"; # 1 2 3
say $msg; # three items
Η παγίδα: δεν υπάρχει μία μόνο απάντηση στο «τι κάνει αυτός ο πίνακας» - εξαρτάται από την περιβάλλουσα έκφραση, εκεί που η Lua επιλύει το άπλωμα πολλαπλών τιμών μόνο στο συγκεκριμένο σημείο κλήσης. Όταν κάτι επιστρέφει έναν αριθμό που περιμένατε να είναι λίστα (ή το αντίστροφο), το περιβάλλον είναι ο πρώτος ύποπτος. Φτάστε στο scalar για να επιβάλετε ένα πλήθος και σε παρενθέσεις στα αριστερά για να επιβάλετε αντιγραφή στοιχείων.
Αλήθεια τιμών#
Αυτή είναι μια απότομη ρήξη από τη Lua, οπότε επιβραδύνετε. Στη Lua μόνο τα nil και false είναι ψευδή - ο αριθμός 0 και η κενή συμβολοσειρά "" είναι και τα δύο αληθή. Η Perl τραβάει τη γραμμή σε ένα εντελώς διαφορετικό σημείο. Οι ψευδείς τιμές της είναι: ο αριθμός 0, η κενή συμβολοσειρά "", η συμβολοσειρά "0", και το undef (το nil της Perl). Όλα τα άλλα είναι αληθή.
use v5.42;
for my $v (0, 1, "", "0", "00", "0.0", "false") {
say "'$v' is ", ($v ? "true" : "false");
}
Αυτό τυπώνει, ακριβώς:
'0' is false
'1' is true
'' is false
'0' is false
'00' is true
'0.0' is true
'false' is true
Η παγίδα: το ένστικτο ενός προγραμματιστή της Lua ότι το 0 είναι αληθές θα αντιστρέψει σιωπηλά τη σημασία κάθε if ($count). Στην Perl τα 0 και "" είναι ψευδή, οπότε το if ($n) είναι ψευδές όταν το $n είναι μηδέν - συνήθως αυτό που θέλετε, αλλά το αντίθετο της Lua. Από την άλλη μεριά, τα "00" και "0.0" είναι αληθή παρόλο που μοιάζουν αριθμητικά μηδέν, επειδή μόνο η ακριβής συμβολοσειρά "0" είναι ψευδής. Για μια επιλογή «χρησιμοποίησε αυτό αν είναι ορισμένο, αλλιώς μια προεπιλογή» - το ιδίωμα x = y or default της Lua, που σκοντάφτει στα 0 και false - χρησιμοποιήστε το defined-or // της Perl, που πέφτει πίσω μόνο στο undef (το nil της Perl):
use v5.42;
my %cfg = (host => "localhost");
my $port = $cfg{port} // 8080; # key absent -> undef -> 8080
say $port; # 8080
Ροή ελέγχου#
Οι δεσμευμένες λέξεις είναι οικείες· η γραφή διαφέρει. Το elseif της Lua είναι το elsif της Perl, δεν υπάρχει then/do/end, και τα μπλοκ είναι σε άγκιστρα αντί να οριοθετούνται με δεσμευμένες λέξεις.
if n < 0 then
sign = "neg"
elseif n == 0 then
sign = "zero"
else
sign = "pos"
end
for _, x in ipairs(nums) do
print(x)
end
while running do
step()
end
use v5.42;
my $sign;
if ($n < 0) { $sign = "neg" }
elsif ($n == 0) { $sign = "zero" }
else { $sign = "pos" }
for my $x (@nums) { say $x }
while ($running) { step() }
Η Perl προσθέτει δύο πράγματα που δεν έχει η Lua. Οι μεταθεματικοί τροποποιητές επιτρέπουν σε μια απλή εντολή να φέρει τη δική της συνθήκη ή βρόχο, κάτι που διαβάζεται φυσικά για μονόγραμμα:
use v5.42;
say $_ for @nums; # loop, one statement
say "negative" if $n < 0; # guarded statement
$sum += $_ for @nums; # accumulate
Και τα unless/until είναι οι αρνημένες μορφές των if/while, για όταν η θετική διατύπωση διαβάζεται αδέξια: say "ok" unless $error.
Η παγίδα: η Perl δεν έχει εντολή x if c else y· η εκφραση υπό συνθήκη είναι ο τριαδικός τελεστής σε στυλ C με ?/:, τον οποίο η Lua συνήθως απομιμείται με c and x or y. Η μορφή της Perl είναι άμεση και αλυσιδώνεται: my $sign = $n < 0 ? "neg" : $n == 0 ? "zero" : "pos". Ο έλεγχος βρόχου είναι last/next εκεί που η Lua έχει break και (στην 5.4) goto continue.
Υπορουτίνες#
Το function γίνεται sub. Η σύγχρονη Perl έχει υπογραφές που ονοματίζουν τις παραμέτρους τους, συμπεριλαμβανομένων των προεπιλογών, αντί για το θεσιακό ... και τον χειροκίνητο χειρισμό arg της Lua.
local function greet(name, greeting)
greeting = greeting or "Hello"
return greeting .. ", " .. name .. "!"
end
local function total(...)
local sum = 0
for _, n in ipairs({...}) do sum = sum + n end
return sum
end
use v5.42;
sub greet ($name, $greeting = "Hello") {
return "$greeting, $name!";
}
say greet("Ada"); # Hello, Ada!
say greet("Linus", "Hi"); # Hi, Linus!
sub total (@nums) {
my $sum = 0;
$sum += $_ for @nums;
return $sum;
}
say total(1, 2, 3, 4); # 10
Το ιδίωμα ονοματισμένων ορισμάτων της Lua (το πέρασμα ενός μοναδικού table, f{host=..., port=...}) αντιστοιχίζεται σε μια παράμετρο hash, αφού τα ζεύγη key => value ισοπεδώνονται σε μια λίστα που μια υπογραφή %opts συγκεντρώνει:
use v5.42;
sub connect_to (%opts) {
return "host=$opts{host} port=$opts{port}";
}
say connect_to(host => "localhost", port => 8080);
# host=localhost port=8080
Η παγίδα: μια sub επιστρέφει την τιμή της τελευταίας της έκφρασης ακόμη και χωρίς return (όπως η μόνο-ρητή επιστροφή της Lua, μόνο που η Perl έχει επίσης τη σιωπηρή μορφή της τελευταίας τιμής), και η επιστροφή είναι ευαίσθητη στο περιβάλλον (δείτε Περιβάλλον). Αν κάνετε return @list, ο καλών παίρνει τη λίστα σε περιβάλλον λίστας αλλά το πλήθος σε βαθμωτό περιβάλλον - ένας βαθμός ελευθερίας που η πολλαπλή επιστροφή της Lua δεν έχει.
Αναφορές#
Οι πίνακες και τα hashes της Perl δεν εμφωλεύονται απευθείας· τα εμφωλεύετε μέσω αναφορών, ενός βαθμωτού που δείχνει σε ένα σύνολο. Στη Lua κάθε table είναι ήδη αναφορά (η ανάθεση ενός table το μοιράζεται, ποτέ δεν το αντιγράφει), οπότε αυτή η έννοια είναι εκεί αόρατη σε εσάς· στην Perl παίρνετε μια αναφορά ρητά με \, και την ακολουθείτε με ->.
local data = {name = "Ada", langs = {"Perl", "Lua"}}
print(data.langs[2]) -- Lua
table.insert(data.langs, "Ruby")
use v5.42;
my $data = { name => "Ada", langs => ["Perl", "Lua"] };
say $data->{name}; # Ada
say $data->{langs}[1]; # Lua
push $data->{langs}->@*, "Ruby"; # postfix deref to push
say "@{$data->{langs}}"; # Perl Lua Ruby
Το { ... } φτιάχνει μια ανώνυμη αναφορά hash και το [ ... ] μια ανώνυμη αναφορά πίνακα - τα κυριολεκτικά δομικά στοιχεία των εμφωλευμένων δεδομένων. Το βέλος -> ακολουθεί μια αναφορά κατά ένα βήμα· ανάμεσα σε δύο δείκτες είναι προαιρετικό, οπότε τα $data->{langs}[1] και $data->{langs}->[1] είναι ίδια.
Οι ανώνυμες subs είναι πραγματικά closures, ακριβώς όπως τα closures της Lua πάνω από upvalues - μία από τις πιο καθαρές μεταφορές σε όλον τον οδηγό:
use v5.42;
sub counter ($start) {
my $n = $start;
return sub { return $n++ };
}
my $c = counter(10);
say $c->(); # 10
say $c->(); # 11
say $c->(); # 12
Η παγίδα: οι μεταθεματικές μορφές αποαναφοράς (->@*, ->%*, ->$*) είναι ο σύγχρονος, ευανάγνωστος τρόπος να αποαναφέρετε ένα ολόκληρο σύνολο, και το "@{ ... }" είναι ο τρόπος να παρεμβάλετε έναν αποαναφερμένο πίνακα μέσα σε μια συμβολοσειρά. Οι παλαιότερες μορφές @$ref και ${$ref}{key} εξακολουθούν να δουλεύουν και εμφανίζονται σε υπάρχοντα κώδικα, αλλά προτιμήστε το βέλος και τις μεταθεματικές μορφές σε νέο κώδικα.
Κανονικές εκφράσεις#
Αυτό είναι αναβάθμιση, όχι μετάφραση. Η Lua έχει μοτίβα - string.match, string.gsub, κλάσεις χαρακτήρων όπως το %d - τα οποία εσκεμμένα δεν είναι κανονικές εκφράσεις και τους λείπει η εναλλαγή, οι ποσοδείκτες, και οι οπισθαναφορές. Η Perl έχει πλήρες regex ως σύνταξη: το =~ συνδέει ένα μοτίβο με μια συμβολοσειρά, το m// αντιστοιχίζει, το s/// αντικαθιστά. Οι ομάδες σύλληψης καταλήγουν στα $1, $2, και οι ονομαστικές συλλήψεις στο %+.
local s = "2026-06-20"
local y, m, d = string.match(s, "(%d+)-(%d+)-(%d+)")
local t = string.gsub("a,b,c", ",", ";") -- a;b;c
use v5.42;
my $s = "2026-06-20";
if ($s =~ /(\d{4})-(\d{2})-(\d{2})/) {
say "$1 $2 $3"; # 2026 06 20
}
if ($s =~ /(?<year>\d{4})/) {
say $+{year}; # 2026
}
(my $t = "a,b,c") =~ s/,/;/g; # a;b;c
my @parts = split /,/, "one,two,three"; # one two three
Μια αντιστοίχιση /g σε περιβάλλον λίστας επιστρέφει όλες τις αντιστοιχίες, το άμεσο αντίστοιχο της επανάληψης string.gmatch:
use v5.42;
my @nums = "x1y2z3" =~ /(\d)/g; # 1 2 3
say "@nums";
Η παγίδα: οι μετα-χαρακτήρες διαφέρουν από τα μοτίβα της Lua - η Perl χρησιμοποιεί \d εκεί που η Lua χρησιμοποιεί %d, ποσοδείκτες */+/?, εναλλαγή |, και ονομαστικές ομάδες (?<name>...), καμία από τις οποίες δεν υποστηρίζουν τα μοτίβα της Lua. Και το s/// τροποποιεί τον στόχο του επιτόπια και επιστρέφει τον αριθμό των αντικαταστάσεων, όχι μια νέα συμβολοσειρά, εκεί που το gsub της Lua επιστρέφει μια νέα συμβολοσειρά. Γι” αυτό το παράδειγμα αντιγράφει πρώτα με (my $t = "a,b,c") και μετά αντικαθιστά στο αντίγραφο. Για να πάρετε μια νέα συμβολοσειρά χωρίς να αγγίξετε την αρχική, χρησιμοποιήστε τη σημαία /r: my $t = $s =~ s/,/;/gr.
I/O αρχείων και ροών#
Το ιδίωμα είναι το open με τρία ορίσματα και ένα λεξιλογικό filehandle, το αντίστοιχο του io.open της Lua. Ο τελεστής με γωνιώδεις αγκύλες <$fh> διαβάζει μια γραμμή, τον ρόλο του fh:read("l") ή του επαναλήπτη fh:lines() της Lua.
local f = io.open("/tmp/sample.txt", "w")
for i = 1, 3 do
f:write("line " .. i .. "\n")
end
f:close()
f = io.open("/tmp/sample.txt", "r")
for line in f:lines() do
print("got:", line)
end
f:close()
use v5.42;
my $path = "/tmp/sample.txt";
open my $wh, '>', $path or die "cannot write: $!";
print {$wh} "line $_\n" for 1 .. 3;
close $wh;
open my $rh, '<', $path or die "cannot read: $!";
while (my $line = <$rh>) {
chomp $line;
say "got: $line"; # got: line 1 ... got: line 3
}
close $rh;
Για να ρουφήξετε (slurp) όλες τις γραμμές μονομιάς, διαβάστε το handle σε περιβάλλον λίστας:
use v5.42;
open my $fh, '<', "/tmp/sample.txt" or die $!;
my @lines = <$fh>; # all lines, including newlines
say scalar @lines; # 3
Η παγίδα: μια γραμμή που διαβάστηκε με <$fh> κρατάει τον τελικό χαρακτήρα νέας γραμμής (το fh:lines() της Lua τον αφαιρεί, το fh:read("L") τον κρατάει)· καλέστε chomp για να τον αφαιρέσετε. Και το open επιστρέφει ψευδές σε αποτυχία αντί να εγείρει εξαίρεση, όπως ακριβώς το io.open της Lua επιστρέφει nil, err, οπότε το ιδίωμα or die "...: $!" είναι υποχρεωτικό - το $! είναι το μήνυμα σφάλματος συστήματος, το errno της Perl.
Αρθρώματα και πακέτα#
Το require της Lua γίνεται το use της Perl. Ο διαχωριστής χώρου ονομάτων είναι το ::, όχι το ., και ένα άρθρωμα Foo::Bar βρίσκεται στο Foo/Bar.pm στη διαδρομή ένταξης @INC (το package.path της Lua). Σε αντίθεση με το require της Lua, που επιστρέφει ένα table που αναθέτετε εσείς, το use εισάγει επιλεγμένα ονόματα απευθείας στον χώρο ονομάτων σας.
local sqrt = math.sqrt
local sum = 0
for i = 1, 10 do sum = sum + i end
use v5.42;
use List::Util qw(sum0 max first);
say sum0(1 .. 10); # 55
say max(3, 7, 2); # 7
say first { $_ % 2 == 0 } (1, 3, 4, 5); # 4
Εδώ είναι μια ευχάριστη έκπληξη ερχόμενοι από τη σκόπιμα μικροσκοπική τυπική βιβλιοθήκη της Lua: η Perl έρχεται με ένα μεγάλο ενσωματωμένο σύνολο, και πολλά από αυτά που θα έφτιαχνες με το χέρι ή θα τραβούσες από το LuaRocks είναι στον πυρήνα ή ένα use μακριά στο CPAN, το αρχείο πακέτων της Perl. Τα List::Util, Scalar::Util, POSIX, File::Spec, και Data::Dumper είναι τα καθημερινά.
Η παγίδα: το use τρέχει κατά τη μεταγλώττιση, όχι στη γραμμή όπου εμφανίζεται, οπότε η τοποθέτησή του σε σχέση με τον κώδικά σας δεν έχει σημασία όπως έχει μια κλήση require. Η εισαγωγή είναι προαιρετική ανά όνομα: το use List::Util qw(sum0 max) φέρνει ακριβώς τα sum0 και max στον χώρο ονομάτων σας, τίποτε άλλο.
Αντικείμενα#
Η Lua δεν έχει ενσωματωμένο σύστημα αντικειμένων· χτίζετε ένα από tables και metatables - setmetatable(t, {__index = Class}) για αναζήτηση μεθόδου και κληρονομικότητα, __add/__eq για τελεστές. Η Perl 5.42 σας δίνει αντ” αυτού μια σύνταξη class πρώτης τάξης, οπότε η συνηθισμένη περίπτωση δεν χρειάζεται καλωδίωση metatable. Τα πεδία δηλώνονται με field, οι μέθοδοι με method, και το $self είναι διαθέσιμο μέσα σε κάθε μέθοδο (δεν το περνάτε ως την πρώτη παράμετρο όπως κάνει το self / η κλήση με άνω-κάτω-τελεία της Lua).
local Point = {}
Point.__index = Point
function Point.new(x, y)
return setmetatable({x = x or 0, y = y or 0}, Point)
end
function Point:to_string()
return "(" .. self.x .. ", " .. self.y .. ")"
end
function Point:move(dx, dy)
self.x = self.x + dx
self.y = self.y + dy
return self
end
local p = Point.new(3, 4)
print(p:to_string()) -- (3, 4)
p:move(1, 1)
print(p:to_string()) -- (4, 5)
use v5.42;
use feature 'class';
class Point {
field $x :param = 0;
field $y :param = 0;
method to_string { return "($x, $y)" }
method move ($dx, $dy) {
$x += $dx;
$y += $dy;
return $self;
}
}
my $p = Point->new(x => 3, y => 4);
say $p->to_string; # (3, 4)
$p->move(1, 1);
say $p->to_string; # (4, 5)
Ο κατασκευαστής δημιουργείται για εσάς, αντικαθιστώντας το γραμμένο-με-το-χέρι Point.new της Lua: το :param σημειώνει ένα πεδίο που η αυτόματα κατασκευασμένη new δέχεται ως ονοματισμένο όρισμα, και το = 0 είναι η προεπιλογή του. Η κληρονομικότητα, την οποία η Lua χτίζει από μια αλυσίδα metatables __index, είναι το attribute :isa:
use v5.42;
use feature 'class';
class Point3D :isa(Point) {
field $z :param = 0;
method z { return $z }
}
my $q = Point3D->new(x => 1, y => 2, z => 3);
say $q->to_string, " z=", $q->z; # (1, 2) z=3
Η παγίδα: το χαρακτηριστικό class εξακολουθεί να σημειώνεται ως πειραματικό στην Perl 5.42, και στο pperl οι ειδοποιήσεις «class is experimental» τυπώνονται στο stderr ακόμη και όταν προσπαθείτε να τις σιγάσετε. Δεν επηρεάζουν την έξοδο του προγράμματός σας, οπότε ένα σενάριο που τυπώνει στο stdout συμπεριφέρεται ακριβώς όπως φαίνεται παραπάνω· απλώς αναμένετε τις ειδοποιήσεις στη ροή σφαλμάτων. Οι μεταμέθοδοι τελεστών της Lua (__add, __eq, και παρόμοιες) αντιστοιχίζονται στην pragma overload της Perl παρά στο class· γι” αυτό, για το παλαιότερο μοντέλο αντικειμένων βασισμένο στο bless, για ρόλους, και για λεπτομέρειες κληρονομικότητας, δείτε τον οδηγό Αντικειμενοστραφούς Προγραμματισμού.
Χειρισμός σφαλμάτων#
Η προστατευμένη κλήση pcall(f) της Lua - που επιστρέφει false, err αντί να ξετυλίγει - έχει δύο αντίστοιχα στην Perl. Το κλασικό τυλίγει κώδικα σε eval { } και εξετάζει το $@ (το σφάλμα που πιάστηκε) μετά:
local ok, err = pcall(function() risky(-1) end)
if not ok then
print("caught: " .. err)
end
use v5.42;
my $result = eval { risky(-1) };
if ($@) {
print "caught: $@"; # caught: negative!
}
Η σύγχρονη μορφή είναι το try/catch, που διαβάζεται πιο πολύ σαν ένα συμβατικό μπλοκ εξαίρεσης παρά σαν τον χορό λογικής-επιστροφής του pcall:
use v5.42;
use feature 'try';
try {
risky(-4);
}
catch ($e) {
print "caught: $e"; # caught: negative!
}
όπου η πλευρά που εγείρει είναι το die, το error της Perl:
use v5.42;
sub risky ($n) {
die "negative!\n" if $n < 0;
return sqrt $n;
}
Η παγίδα: το die με μια συμβολοσειρά που τελειώνει σε \n παράγει ακριβώς αυτό το μήνυμα· το die με μια συμβολοσειρά που δεν τελειώνει σε χαρακτήρα νέας γραμμής παίρνει αυτόματα την προσθήκη " at SCRIPT line N.\n" (το error της Lua κάνει παρόμοιο προθεματισμό θέσης εκτός αν περάσετε επίπεδο 0). Τελειώστε τις συμβολοσειρές σφάλματός σας με \n όταν θέλετε ένα καθαρό μήνυμα και παραλείψτε το όταν θέλετε το ίχνος αρχείου-και-γραμμής. Σημειώστε επίσης τις δύο μεταβλητές σφάλματος: το $@ είναι η τελευταία εξαίρεση που πιάστηκε, ενώ το $! είναι το τελευταίο σφάλμα συστήματος (ένα αποτυχημένο open, η συμβολοσειρά errno).
Ιδιωματισμοί#
Μερικά μοτίβα που θα βλέπετε καθημερινά και θα θέλετε στα δάχτυλά σας.
Ταξινομήστε μια λίστα με βάση ένα υπολογισμένο κλειδί (ο Schwartzian transform - διακόσμησε, ταξινόμησε, αφαίρεσε τη διακόσμηση σε μία σωλήνωση, το αντανακλαστικό της Perl εκεί που η Lua περνάει μια συνάρτηση συγκριτή στο table.sort):
use v5.42;
my @words = qw(apple fig pear);
my @by_length =
map { $_->[1] }
sort { $a->[0] <=> $b->[0] }
map { [ length $_, $_ ] } @words;
say "@by_length"; # fig pear apple
Φτιάξτε ένα hash από μια λίστα, μετατρέποντας μια ακολουθία σε πίνακα αναζήτησης σε ένα βήμα:
use v5.42;
my @words = qw(apple pear fig);
my %len = map { $_ => length $_ } @words;
say "$_ => $len{$_}" for sort keys %len;
# apple => 5
# fig => 3
# pear => 4
Και το pperl είναι ένα εργαλείο γραμμής εντολών στην εξειδικευμένη θέση των awk/sed, έναν ρόλο που η Lua δεν στοχεύει. Το μονόγραμμο με σιωπηρό βρόχο είναι το καθημερινό αντανακλαστικό του προγραμματιστή της Perl:
pperl -lane '$s += $F[-1]; END { print $s }' data.txt
Η παγίδα: διαβάστε τον οδηγό Μονόγραμμων για τους διακόπτες (-n, -p, -a, -l, -e) και τις δεκάδες συνταγές που είναι χτισμένες πάνω τους· είναι ένα από τα πράγματα με τη μεγαλύτερη μόχλευση που μπορείτε να μάθετε ερχόμενοι από υπόβαθρο scripting όπου αυτή η εξειδικευμένη θέση ήταν δουλειά κάποιου άλλου.
Παγίδες ερχόμενοι από τη Lua#
Οι παγίδες, συγκεντρωμένες για μια τελική σάρωση πριν αρχίσετε να γράφετε:
Ένα table γίνεται δύο τύποι. Ένα table της Lua είναι ένας
@array(με ακέραια κλειδιά, διατεταγμένος) ή ένα%hash(με κλειδιά συμβολοσειρών, αδιάτακτο) στην Perl, ποτέ και τα δύο μαζί. Αποφασίστε ποιο έχετε πριν το χρησιμοποιήσετε.Οι πίνακες είναι 0-based. Το
t[1]της Lua είναι το$t[0]της Perl· το τελευταίο στοιχείο είναι$t[-1]. Αυτό είναι το πιο συχνό σφάλμα ολίσθησης-κατά-ένα κατά τη μεταφορά.Τα sigils αλλάζουν με τη χρήση. Ένα στοιχείο του
@aείναι$a[0]· μία τιμή του%hείναι$h{k}. Το sigil του περιέκτη και το sigil του στοιχείου διαφέρουν - το σκέτο όνομαtτης Lua δεν έχει τέτοια μετατόπιση.Η συνένωση είναι
., όχι... Το..της Lua δεν υπάρχει· το.ενώνει συμβολοσειρές και τοxτις επαναλαμβάνει.Η αλήθεια είναι αντεστραμμένη στο μηδέν. Στη Lua τα
0και""είναι αληθή· στην Perl είναι ψευδή. Μόνο τα0,"","0", καιundefείναι ψευδή, οπότε τα"00"και"0.0"είναι παραδόξως αληθή.Δύο οικογένειες σύγκρισης.
==/</<=>για αριθμούς,eq/lt/cmpγια συμβολοσειρές. Επιλέξτε με βάση τον τύπο του τελεστέου· το μοναδικό==της Lua δεν έχει αντίστοιχο διαχωρισμό.Το
sortταξινομεί ως συμβολοσειρές από προεπιλογή. Περάστε{ $a <=> $b }για αριθμητική σειρά.Περιβάλλον. Το
my $x = @aείναι το μήκος· τοmy ($x) = @aείναι το πρώτο στοιχείο. Η μορφή λίστας είναι ο φίλος σαςlocal a, b = f()· η βαθμωτή μορφή είναι καινούργια. Ξαναδιαβάστε το Περιβάλλον όταν μια τιμή επιστρέφει με λάθος σχήμα.Το regex δεν είναι τα μοτίβα της Lua. Η Perl έχει πλήρες regex (
\d,|,*, ονομαστικές ομάδες)· τα μοτίβα της Lua (%d, χωρίς εναλλαγή) είναι μια διαφορετική, μικρότερη γλώσσα. Τοs///επεξεργάζεται επιτόπια και επιστρέφει ένα πλήθος· χρησιμοποιήστε/rγια μια νέα συμβολοσειρά.Το
openδεν εγείρει εξαίρεση. Χρησιμοποιήστεopen ... or die "...: $!", όπως τοio.openτης Lua επιστρέφειnil, err.Κάντε
chompστις αναγνώσεις γραμμών σας. Το<$fh>κρατάει τον τελικό χαρακτήρα νέας γραμμής που τοlines()της Lua θα είχε αφαιρέσει.Η μη-ASCII πηγή χρειάζεται
use utf8;. Υπόuse v5.42;ένα κυριολεκτικό μη-ASCII byte στην πηγή σας είναι σφάλμα μεταγλώττισης χωρίς αυτό. Κρατήστε τα δεδομένα συμβολοσειρών ASCII εκτός αν προσθέσετε ρητάuse utf8;.The
classfeature prints experimental notices to stderr onpperl. Correct output, noisy error stream. Operator metamethods map to theoverloadpragma, not toclass.