Joh: Array als Membervariable

Hallo Leute,

im Rahmen einer kleineren Aufgabe wollte ich mir soeben schnell ein Perl-Script basteln, das die Fleißarbeit übernimmt. Ich habe meinen Quellcode für hier mal heruntergebrochen auf den entscheidenden Teil.

sub new  
{  
	my @a = ('a', 'b');  
	bless {'windows' => \@a}, shift;  
}  
  
sub print  
{  
	my $self = shift;  
	print "Elemente: " . $self->{'windows'} . "\n";  
}

Ausgabe, wie erwartet: Elemente: ARRAY(0x6aeb9c)

Also dereferenzieren wir das Array vor dem Zugriff:

sub new  
{  
	my @a = ('a', 'b');  
	bless {'windows' => \@a}, shift;  
}  
  
sub print  
{  
	my $self = shift;  
	print "Elemente: " . @$self->{'windows'} . "\n";  
}

Ausgabe: Not an ARRAY reference at blabla.pm line 12.

Was denn nun? Naja, befüllen wir das Objekt also ganz direkt, erstmal mit einem leeren Array.

sub new { bless {'windows' => ()}, shift; }  
  
sub print  
{  
	my $self = shift;  
	print "Elemente (" . $self->{'windows'} . "): " . join(',', $self->{'windows'}) . "\n";  
	$i = 0;  
	print "\tElement " . $i++ . ": " . $_ . "\n" foreach $self->{'windows'};  
}

Erwartete Ausgabe:

Elemente (0):

Tatsächliche Ausgabe:

Elemente ():
        Element 0:

Die foreach-Schleife läuft also einen Schritt durch das leere Array? Naja, also können wir es ja mal füllen und schauen, was dann passiert.

sub new { bless {'windows' => ('a', 'b')}, shift; }  
  
sub print  
{  
	my $self = shift;  
	print "Elemente (" . $self->{'windows'} . "): " . join(',', $self->{'windows'}) . "\n";  
	$i = 0;  
	print "\tElement " . $i++ . ": " . $_ . "\n" foreach $self->{'windows'};  
}

Erwartete Ausgabe:

Elemente (2): a,b
        Element 0: a
Element 1: b

Ausgabe:

Elemente (a): a
        Element 0: a

Das zweite Element fehlt einfach, und bei der Konvertierung des Arrays in einen Skalar wird das erste Element zurückgegeben, statt der Länge? Vielleicht haut ja hier etwas mit dem Objekt selber nicht hin. Speichern wir mal testweise einen String, statt ein Array.

sub new { bless {'windows' => 'Hello'}, shift; }  
  
sub print  
{  
	my $self = shift;  
	print $self->{'windows'} . " world!\n";  
}

Ausgabe, wie erwartet: Hello world!

Also, entweder die Welt ist durchgeknallt, oder ich. Scheinbar habe ich hier wohl etwas ganz elementares nicht verstanden. Es muss doch möglich sein, ein Array in einem Objekt zu speichern?

Johannes

  1. hi,

    Also, entweder die Welt ist durchgeknallt, oder ich. Scheinbar habe ich hier wohl etwas ganz elementares nicht verstanden. Es muss doch möglich sein, ein Array in einem Objekt zu speichern?

    Natürlich geht das. Als Referenz ;)

      
    sub new{  
      my $class = shift;  
      return bless {ARRAY => []}, $class;  
    }  
      
    sub load{  
      my $self = shift;  
      $self->{ARRAY} = \@_;  
    }  
      
    sub print{  
      my $self = shift;  
      print join "\n", @{$self->{ARRAY}};  
    }  
      
    my $aol = main->new;  
    $aol->load(1,2,3,4,5);  
    $aol->print;  
      
    
    

    Hotti

    1. Ah, auch die Werte in Hashes müssen immer skalar sein, verstehe. Und gemäß Operatorenvorrang ist @$a->b == (@$a)->b. Na gut! Danke für den funktionierenden Code, es läuft. Freue mich, danke!! :)

  2. Hallo,

    sub print
    {
    my $self = shift;
    print "Elemente: " . @$self->{'windows'} . "\n";
    }

    
    >   
    > Ausgabe: Not an ARRAY reference at blabla.pm line 12.  
      
    $self ist auch kein arrayref.  
      
    ~~~perl
      
    foreach my $item (@{$self->{windows}})  
    {  
      print;  
    }  
    
    

    sub new { bless {'windows' => ()}, shift; }

    das ist kein arrayref.

    z.B. http://perldoc.perl.org/perlref.html

    Hth

    1. Ah, auch die Werte in Hashes müssen immer skalar sein, verstehe. Und gemäß Operatorenvorrang ist @$a->b == (@$a)->b. Na gut! Hab entsprechend nachkorrigiert und es läuft. Freue mich, danke!! :)

  3. Also dereferenzieren wir das Array vor dem Zugriff:
        @$self->{'windows'}

    Es muss @{ $self->{'windows'} } heißen. Hättest du perlcritic eingesetzt, monierte es dir diese Verwendung von Doppelsigiln.

    Was denn nun?

    Du hattest eine Meinungsverschiedenheit mit Perl über die Rangreihenfolge der Dereferenzierung. Perl gewinnt immer in Meinungsverschiedenheiten. Es ist immer eine gute Idee, so zu programmieren, dass Meinungsverschiedenheiten nicht im Code auftreten können. Werkzeuge und Praktiken helfen dir dabei. Setze sie ein.

    Naja, befüllen wir das Objekt also ganz direkt, erstmal mit einem leeren Array.
        sub new { bless {'windows' => ()}, shift; }

    Das ist nicht sinnvoll. Dein Objekt ist hashbasiert. Schlüssel und Werte in einem Hash sind immer skalare Werte. Du hast da eine (leere) Liste. Listen sind nicht skalar. Du musst eine (leere) Arrayreferenz einsetzen. Dies ist, wie alle Referenzen, ein skalarer Wert.
        sub new { bless {'windows' => []}, shift; }

    Der Fehler wäre dir von allein aufgefallen, wenn du zuerst einen Hash erzeugt hättest, anstatt gleich eine anonyme Referenz zu blessen.
        ~~~perl

    use warnings;
        my %obj = (
            'windows' => ('a', 'b')
        );

    Odd number of elements in hash assignment at…

    
    > Scheinbar habe ich hier wohl etwas ganz elementares nicht verstanden.  
    
    Referenzen bzw. deren korrekte Verwendung. Bitte schlage das in deinem Perllehrbuch oder in der Dokumentation nach.  
      
    Hausaufgabe: Erkläre die Warnung im vorletzten Absatz!
    
    1. Ah, auch die Werte in Hashes müssen immer skalar sein, verstehe. Und gemäß Operatorenvorrang ist @$a->b == (@$a)->b. Na gut! Hab entsprechend nachkorrigiert und es läuft. Freue mich, danke!! :)