EMZETT.
Login

Kurz: Arrays und Hashes enthalten nur Skalare. Für verschachtelte Strukturen braucht man Referenzen: Skalare, die auf andere Daten zeigen.

Teil des Kurses Perl

Kapitel 8 von 11 im Kurs Perl. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Referenzen

Arrays und Hashes enthalten nur Skalare. Für verschachtelte Strukturen braucht man Referenzen: Skalare, die auf andere Daten zeigen.

use strict; use warnings;
my @liste = (1, 2, 3);
my %hash = (a => 1, b => 2);
my $aref = \@liste;               # Referenz auf Array
my $href = \%hash;
my $cref = sub { "Hallo $_[0]" };
my $sref = \"Text";
 
print "$$aref[0] ${$aref}[1] $aref->[2]\n";        # drei Schreibweisen
print "$href->{a} $$href{b}\n";
print scalar(@$aref), " Elemente\n";
print join(",", sort keys %$href), "\n";
print $cref->("Welt"), "\n";
print $$sref, "\n";
print ref($aref), " ", ref($href), " ", ref($cref), " ", ref($sref), " ", ref(\$aref), "\n";
push @$aref, 4;
print "@liste\n";                  # das Original wurde geändert
my @kopie = @$aref;                # echte Kopie
$kopie[0] = 99;
print "$liste[0]\n";

Ausgabe:

1 2 3
1 2
3 Elemente
a,b
Hallo Welt
Text
ARRAY HASH CODE SCALAR REF
1 2 3 4
1

Verschachtelte Strukturen

Mit anonymen Arrays [...] und Hashes {...} baust du beliebig tiefe Daten:

use strict; use warnings;
my %firma = (
    name => "Emzett",
    mitarbeiter => [
        { name => "Mia", rolle => "Dev", skills => ["perl", "sql"] },
        { name => "Tom", rolle => "Ops", skills => ["bash"] },
    ],
    adresse => { ort => "Berlin", plz => "10115" },
);
 
print "Firma: $firma{name} in $firma{adresse}{ort}\n";
print "Erste Person: $firma{mitarbeiter}[0]{name}\n";
print "Skills von Mia: @{ $firma{mitarbeiter}[0]{skills} }\n";
push @{ $firma{mitarbeiter} }, { name => "Zoe", rolle => "Dev", skills => [] };
print "Anzahl: ", scalar @{ $firma{mitarbeiter} }, "\n";
 
for my $m (@{ $firma{mitarbeiter} }) {
    printf "%-4s %-4s %s\n", $m->{name}, $m->{rolle}, join("/", @{ $m->{skills} }) || "-";
}
my @devs = grep { $_->{rolle} eq "Dev" } @{ $firma{mitarbeiter} };
print join(", ", map { $_->{name} } @devs), "\n";
my %nach_rolle;
push @{ $nach_rolle{ $_->{rolle} } }, $_->{name} for @{ $firma{mitarbeiter} };    # Autovivification
print join("; ", map { "$_: @{ $nach_rolle{$_} }" } sort keys %nach_rolle), "\n";
print exists $firma{adresse}{strasse} ? "Straße" : "keine Straße", "\n";
my @matrix = ([1, 2, 3], [4, 5, 6]);
print $matrix[1][2], " ", scalar(@{ $matrix[0] }), " ", join(",", map { $_->[0] } @matrix), "\n";

Ausgabe:

Firma: Emzett in Berlin
Erste Person: Mia
Skills von Mia: perl sql
Anzahl: 3
Mia  Dev  perl/sql
Tom  Ops  bash
Zoe  Dev  -
Mia, Zoe
Dev: Mia Zoe; Ops: Tom
keine Straße
6 3 1,4

Autovivification: Perl legt fehlende Zwischenebenen automatisch an, sobald du darauf schreibst ($h{a}{b}{c} = 1).

Postfix-Dereferenzierung

Ab Perl 5.24 lesbarer:

use v5.36;
my $a = [3, 1, 2];
my $h = { x => 1, y => 2 };
say join ",", sort { $a <=> $b } $a->@*;
say scalar $a->@*;
say join ",", sort keys $h->%*;
say "Letzter Index: ", $a->$#*;
my @teil = $a->@[0, 1];
say "@teil";

Ausgabe:

2,1,3
3
x,y
Letzter Index: 2
3 1

Daten ausgeben: Data::Dumper

use strict; use warnings;
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Indent = 1;
my $daten = { name => "Mia", liste => [1, 2], tief => { a => undef } };
print Dumper($daten);
$Data::Dumper::Terse = 1;
$Data::Dumper::Indent = 0;
print Dumper([1, { k => "v" }]), "\n";

Ausgabe:

$VAR1 = {
  'liste' => [
    1,
    2
  ],
  'name' => 'Mia',
  'tief' => {
    'a' => undef
  }
};
[1,{'k' => 'v'}]

Kopieren und Gleichheit

use strict; use warnings;
use Storable qw(dclone);
my $orig = { liste => [1, 2, 3] };
my $flach = { %$orig };            # flache Kopie: Liste wird geteilt
my $tief = dclone($orig);          # tiefe Kopie
push @{ $orig->{liste} }, 4;
print scalar @{ $flach->{liste} }, " ", scalar @{ $tief->{liste} }, "\n";
print "gleiche Referenz\n" if $orig == $orig;
print "verschiedene Referenzen\n" if $orig != $tief;

Ausgabe:

4 3
gleiche Referenz
verschiedene Referenzen

Merke

  • \@a, \%h, \&f bilden Referenzen; [...] und {...} erzeugen anonyme
  • Zugriff: $r->[0], $r->{key}, @{$r}, %{$r}, $r->@*
  • Verschachtelte Daten: $d{liste}[0]{name}
  • ref() zeigt den Typ; Data::Dumper gibt Strukturen aus
  • Flache vs. tiefe Kopie (Storable::dclone)

Übungsaufgabe

Baue eine Liste von Büchern (Hashes) und gruppiere sie nach Autor in einem Hash von Arrays.

Quiz zur Selbstkontrolle

?

  • Eine Referenz auf ein anonymes Array (richtig)
  • Ein Array
  • Einen Hash
  • Eine Funktion

Weiter im Kurs

Zurück: Dateien, Verzeichnisse und Ein-/Ausgabe

Weiter: Module, CPAN und Pakete

Alle Kapitel: Perl im Überblick