Datentypen
Perl hat drei grundlegende Datentypen: Skalare, Arrays und Hashes. PetaPerl implementiert diese mit identischer Semantik zu Perl 5.
Skalare
Skalare sind der grundlegende Datentyp in Perl und enthalten einen einzelnen Wert. Der Variablenname beginnt mit $.
my $number = 42;
my $string = "hello";
my $float = 3.14;
my $ref = \@array;
Skalartypen
Intern stellt PetaPerl Skalare als Enum mit folgenden Varianten dar:
| Typ | Beschreibung | Beispiel |
|---|---|---|
Undef | Undefinierter Wert | undef |
Iv | Ganzzahl (i64) | 42, -17 |
Uv | Vorzeichenlose Ganzzahl (u64) | Grosse positive Zahlen |
Nv | Gleitkommazahl (f64) | 3.14, 1.5e10 |
Pv | Unveraenderliche Zeichenkette (Arc<str>) | Konstanten, Literale |
PvBuf | Veraenderliche Zeichenkette (Arc<String>) | .=-Ziele, $_ |
Rv | Referenz | \$x, \@arr, \%hash |
Av | Array | Erzeugt durch [] |
Hv | Hash | Erzeugt durch {} |
Dynamische Typisierung: Ein Skalar kann seinen Typ waehrend der Ausfuehrung aendern.
my $x = 42; # Ganzzahl
$x = "hello"; # Jetzt eine Zeichenkette
$x = 3.14; # Jetzt eine Gleitkommazahl
Skalarer Kontext
Operationen, die einen einzelnen Wert erwarten, erzwingen skalaren Kontext:
my $count = @array; # Array-Laenge
my $last = (1, 2, 3); # Letztes Element (3)
if (@array) { ... } # Wahr wenn nicht leer
Spezielle Skalare
| Wert | Beschreibung |
|---|---|
undef | Undefinierter Wert |
0 | Numerische Null, Zeichenkette “0” |
"" | Leere Zeichenkette |
Wahrheitswerte: Diese sind im booleschen Kontext falsch: undef, 0, "0", "". Alles andere ist wahr.
if ($value) { ... } # Falsch bei undef, 0, "0" oder ""
if (defined $value) { ... } # Falsch nur bei undef
Arrays
Arrays sind geordnete Listen von Skalaren. Variablennamen beginnen mit @.
my @numbers = (1, 2, 3, 4, 5);
my @words = qw(foo bar baz);
my @empty = ();
Array-Zugriff
my $first = $numbers[0]; # Erstes Element (Index 0)
my $last = $numbers[-1]; # Letztes Element
$numbers[5] = 6; # Element setzen
Beachte den Sigilwechsel: Verwende $ fuer den Zugriff auf ein einzelnes Element, da ein Skalar zurueckgegeben wird.
Array-Laenge
my $length = @array; # Skalarer Kontext
my $length = scalar @array; # Explizit skalarer Kontext
my $max_index = $#array; # Hoechster Index (Laenge - 1)
Array-Operationen
push @arr, $value; # Anhaengen
my $value = pop @arr; # Letztes entfernen
my $value = shift @arr; # Erstes entfernen
unshift @arr, $value; # Voranstellen
splice @arr, $offset, $len, @replacement; # Allgemeines Entfernen/Einfuegen
Array-Scheiben
Mehrere Elemente auf einmal extrahieren:
my @subset = @arr[0, 2, 4]; # Elemente 0, 2, 4
my @range = @arr[0..5]; # Elemente 0 bis 5
@arr[1, 3] = (10, 20); # Mehreren Elementen zuweisen
Listenkontext
Operationen, die mehrere Werte erwarten, erzwingen Listenkontext:
my @copy = @original; # Array-Kopie
my ($a, $b, $c) = (1, 2, 3); # Listenzuweisung
my @results = function(); # Funktion gibt Liste zurueck
Array-Referenzen
Referenzen auf Arrays erzeugen:
my $aref = \@array; # Referenz auf bestehendes Array
my $aref = [1, 2, 3]; # Anonyme Array-Referenz
Zugriff ueber Referenz:
my $elem = $aref->[0]; # Erstes Element
my @copy = @$aref; # Dereferenzierung zum Array
push @$aref, $value; # Push ueber Referenz
Hashes
Hashes sind ungeordnete Schluessel-Wert-Paare. Variablennamen beginnen mit %.
my %user = (
name => "John",
age => 30,
email => "john@example.com",
);
Hash-Zugriff
my $name = $user{name}; # Wert abrufen
$user{city} = "NYC"; # Wert setzen
Sigilwechsel: Verwende $ fuer den Zugriff auf ein einzelnes Element (es wird ein Skalar zurueckgegeben).
Hash-Operationen
my @keys = keys %hash; # Alle Schluessel
my @values = values %hash; # Alle Werte
while (my ($k, $v) = each %hash) { ... } # Iterieren
if (exists $hash{key}) { ... } # Existenz pruefen
my $val = delete $hash{key}; # Entfernen und zurueckgeben
Hash-Scheiben
Mehrere Werte auf einmal extrahieren:
my @vals = @hash{qw(name age)}; # Werte fuer Schluessel
@hash{qw(x y)} = (10, 20); # Mehrfachzuweisung
Hinweis: Hash-Scheiben verwenden das @-Sigil, da sie eine Liste zurueckgeben.
Hash-Referenzen
Referenzen auf Hashes erzeugen:
my $href = \%hash; # Referenz auf bestehenden Hash
my $href = { key => "val" }; # Anonyme Hash-Referenz
Zugriff ueber Referenz:
my $val = $href->{key}; # Wert abrufen
$href->{new} = "value"; # Wert setzen
my @keys = keys %$href; # Dereferenzierung zum Hash
Referenzen
Referenzen sind Skalare, die auf andere Daten verweisen.
Referenzen erzeugen
my $scalar_ref = \$scalar;
my $array_ref = \@array;
my $hash_ref = \%hash;
my $code_ref = \⊂
my $anon_array = [1, 2, 3];
my $anon_hash = { a => 1, b => 2 };
my $anon_sub = sub { ... };
Dereferenzierung
my $value = $$scalar_ref; # Skalar-Dereferenzierung
my @array = @$array_ref; # Array-Dereferenzierung
my %hash = %$hash_ref; # Hash-Dereferenzierung
my $result = &$code_ref(); # Code-Dereferenzierung
Pfeilnotation (bevorzugt fuer Klarheit):
my $elem = $array_ref->[0];
my $val = $hash_ref->{key};
my $result = $code_ref->(@args);
Referenztypen
Referenztyp mit ref pruefen:
my $type = ref $ref;
# Gibt zurueck: 'SCALAR', 'ARRAY', 'HASH', 'CODE', 'REF' oder '' (keine Referenz)
Verschachtelte Datenstrukturen
Referenzen ermoeglichen komplexe Datenstrukturen:
my $data = {
users => [
{ name => "John", age => 30 },
{ name => "Jane", age => 25 },
],
config => {
debug => 1,
timeout => 30,
},
};
my $name = $data->{users}->[0]->{name}; # "John"
Autovivifikation
Perl erzeugt automatisch Zwischenreferenzen:
my %hash;
$hash{a}{b}{c} = 1; # Erzeugt verschachtelte Hashes automatisch
my $val = $hash{x}[0]; # Erzeugt Array-Referenz unter $hash{x}
Typumwandlungen
Perl fuehrt automatische Typumwandlungen kontextabhaengig durch.
Zeichenkette zu Zahl
my $x = "42";
my $y = $x + 10; # 52 (Zeichenkette -> Zahl)
Zahl zu Zeichenkette
my $x = 42;
my $s = "Wert: $x"; # "Wert: 42" (Zahl -> Zeichenkette)
Zeichenkettenverkettung
my $result = 10 . 20; # "1020" (beide -> Zeichenkette)
Boolescher Kontext
if ("0") { ... } # Falsch
if ("00") { ... } # Wahr
if (0) { ... } # Falsch
if (0.0) { ... } # Falsch
if ("") { ... } # Falsch
if (undef) { ... } # Falsch
Typeglobs
Typeglobs sind ein spezieller Typ, der Eintraege fuer alle Variablentypen mit demselben Namen enthalten kann.
*name = \$scalar; # Glob auf Skalar aliasieren
*name = \⊂ # Glob auf Unterprogramm aliasieren
Werden hauptsaechlich fuer Symboltabellenmanipulation und Importvorgaenge verwendet.
PetaPerl-spezifische Implementierung
Speicherdarstellung
PetaPerl verwendet effiziente interne Darstellungen:
Skalare: Rust-Enum mit Varianten fuer jeden Typ. Zwei Zeichenkettendarstellungen optimieren fuer verschiedene Zugriffsmuster.
#![allow(unused)]
fn main() {
pub enum Sv {
Undef,
Iv(i64), // Ganzzahl
Uv(u64), // Vorzeichenlos
Nv(f64), // Gleitkomma
Pv(Arc<str>, u32), // Unveraenderliche Zeichenkette + virtuelle Laenge (O(1) chomp)
PvBuf(Arc<String>), // Veraenderliche Zeichenkette (COW ueber Arc::make_mut)
Rv(RvInner), // Referenz
Av(Av), // Array
Hv(Hv), // Hash
// ... weitere Typen
}
}
Duale Zeichenkettendarstellung: Pv wird fuer Konstanten und Literale verwendet – die virtuelle Laenge u32 ermoeglicht O(1)-chomp ohne Aenderung der gemeinsam genutzten Zeichenkette. PvBuf wird fuer veraenderliche Zeichenketten verwendet (Standard fuer new_string()) – Arc::make_mut() bietet Copy-on-Write-Semantik ohne Allokation bei nicht geteiltem Besitz.
Arrays: Dynamische Vektoren mit effizienten push/pop-Operationen.
Hashes: Optimierte Hashtabellen mit schneller Schluesselsuche.
Gemeinsamer Besitz
Zeichenketten-Skalare verwenden Arc<str> (atomare Referenzzaehlung):
- Guenstiges Klonen (nur Zaehler erhoehen)
- Thread-sicheres Teilen fuer parallele Ausfuehrung
- Haeufig verwendete Zeichenketten koennen Speicher teilen
Aliasing-Unterstuetzung
PetaPerl implementiert @_-Aliasing korrekt:
- Argumente sind Aliase auf die Variablen des Aufrufers
- Aenderungen schreiben direkt in das Original
- Verwendet
SvCellfuer veraenderliche Indirektion
sub modify {
$_[0] = "changed"; # Aendert die Variable des Aufrufers
}
my $x = "original";
modify($x);
print $x; # "changed"
Leistungsmerkmale
| Operation | Komplexitaet | Anmerkungen |
|---|---|---|
| Skalarzuweisung | O(1) | Zeichenkette nutzt Arc (keine Kopie) |
| Array push/pop | O(1) amortisiert | Dynamisches Wachstum |
| Array shift/unshift | O(n) | Elemente muessen verschoben werden |
| Hash-Zugriff | O(1) durchschnittlich | Optimierte Hash-Funktion |
| Hash-Einfuegen | O(1) durchschnittlich | Mit Wachstum |
Parallele Ausfuehrung
PetaPerls Parallelisierungsmodell:
- Jeder Thread erhaelt seinen eigenen lexikalischen Pad (keine gemeinsame Mutation)
- Array- und Hash-Operationen sind thread-sicher
Arc<str>-Zeichenketten koennen sicher zwischen Threads geteilt werden- Parallelitaet auf Schleifenebene erfordert keine globalen Sperren
Kontextsensitivitaet
Perls Kontextsystem bestimmt, wie Ausdruecke ausgewertet werden.
Skalarer Kontext
Erzwingt Auswertung als Einzelwert:
my $count = @array; # Laenge
my $last = (1, 2, 3); # Letztes Element
my $concat = (1, 2, 3); # 3
Listenkontext
Erzwingt Auswertung als Mehrfachwert:
my @copy = @array; # Alle Elemente
my @results = func(); # Alle Rueckgabewerte
my ($a, $b) = (1, 2, 3); # Erste zwei Elemente
Void-Kontext
Das Ergebnis wird verworfen:
func(); # Rueckgabewert ignoriert
print "hello"; # Keine Zuweisung
Kontextweitergabe
my @arr = (1, 2, 3);
# Skalarer Kontext
my $x = keys @arr; # keys im skalaren Kontext -> Anzahl
# Listenkontext
my @k = keys @arr; # keys im Listenkontext -> alle Schluessel
# Funktionsargument-Kontext
func(@arr); # Listenkontext
func(scalar @arr); # Skalarer Kontext (explizit)
Konstanten
Konstanten sind unveraenderliche Werte.
Literalkonstanten
42 # Ganzzahl
3.14 # Gleitkommazahl
"string" # Zeichenkette
qw(a b c) # Liste von Zeichenketten
Benannte Konstanten
use constant PI => 3.14159;
use constant MAX => 100;
use constant {
RED => 0xFF0000,
GREEN => 0x00FF00,
BLUE => 0x0000FF,
};
Konstantenfaltung zur Uebersetzungszeit
PetaPerl fuehrt Konstantenfaltung zur Uebersetzungszeit durch:
my $x = 2 + 3; # Wird zu 5 gefaltet
my $len = length("hello"); # Wird zu 5 gefaltet
my $sub = substr("text", 0, 2); # Wird zu "te" gefaltet
Diese Optimierung eliminiert Laufzeitberechnungen fuer konstante Ausdruecke.
Spezielle Typen
Code-Referenzen
Unterprogramme koennen referenziert und dynamisch aufgerufen werden:
my $coderef = sub { return $_[0] * 2 };
my $result = $coderef->(21); # 42
my $coderef = \&existing_sub;
$coderef->(@args);
Dateihandles
Dateihandles sind spezielle Skalare:
open my $fh, '<', $file or die $!;
my $line = <$fh>;
close $fh;
Globs
Typeglobs verweisen auf Symboltabelleneintraege:
*alias = *original; # Alle Typen aliasieren
*func = sub { ... }; # Unterprogramm installieren