Frage

Wenn ich eine einfache gebundene Skalarklasse hätte, die sich jedes Mal erhöht, wenn sie gelesen wird, könnte ich das folgendermaßen tun:

package Counter;

use strict;
use warnings;

sub TIESCALAR {
  my $class = shift;
  my $value = 0;

  bless \$value, $class;

  return \$value;
}

sub FETCH {
  my $self = shift;

  my $value = $$self;

  $$self++;

  return $value;
}

sub STORE {
  my $self = shift;
  $$self = shift;
}

1;

Um jedoch eine Zählervariable zu erstellen, muss ich tie verwenden.Ich könnte einen Zähler erstellen und exportieren.Aber was ich wirklich tun möchte, ist, es OO aussehen zu lassen.Es scheint, dass ich eine new-Methode wie diese erstellen könnte:

sub new {
  my $class = shift;
  my $counter;

  tie $counter, $class;

  return $counter;
}

Dann erhalten Sie in meinem Hauptskript zwei Zähler, indem Sie Folgendes tun:

my $counter1 = Counter->new();
my $counter2 = Counter->new();

Ich gehe davon aus, dass dies nicht funktioniert, weil ein Unentschieden eine Kopie nicht überlebt (ich habe das irgendwo in den Dokumenten gelesen). Gibt es einfach keine Möglichkeit, dies zu tun?

NB.Ich weiß, dass es nur eine Frage des Stils ist, aber es würde für das Auge korrekter aussehen.

War es hilfreich?

Lösung

Bindungsmagie wird nicht über die Zuweisung übertragen, da sie für die Variable selbst gilt, nicht für den darin enthaltenen Wert. Sie haben einige Möglichkeiten:

Rückgabe einer Referenz:

sub new {tie my $ret, ...; \$ret}

my $counter = Counter->new;

say $$counter;

Zuweisen zu einem Glob:

our ($counter);

*counter = Counter->new; # same new as above

say $counter;

Oder Sie übergeben die Variable an den Konstruktor:

sub new {my $class = shift; tie $_[0], $class}

Counter->new(my $counter);

say $counter;

Sie können sogar einen Konstruktor erstellen, der mit beiden Methoden funktioniert:

sub new {
    my $class = shift;
    tie $_[0] => $class;
    \$_[0]
}

our $glob; *glob = Counter->new;

Counter->new(my $lexical);

In den letzten beiden Beispielen wird tie direkt an $_[0] übergeben. Der Grund dafür ist, dass die Elemente von @_ Aliase der Argumentliste sind. Es funktioniert also so, als hätten Sie den my $counter in die Zeile tie eingegeben.


Und schließlich, während Ihr Beispiel sehr klar ist und Best Practices folgt, können Sie im Geiste von TIMTOWTDI Ihre gesamte Klasse folgendermaßen schreiben:

{package Counter;
    sub TIESCALAR {bless [0]}
    sub FETCH {$_[0][0]++}
    sub STORE {$_[0][0] = $_[1]}
    sub new {tie $_[1] => $_[0]; \$_[1]}
}


Eine letzte Sache zu erwähnen. Während sich Ihre Frage auf gebundene Variablen bezieht, können Sie auch Überladung verwenden, um dies zu erreichen:

{package Counter;
    use overload fallback => 1, '""' => sub {$_[0][0]++};
    sub new {bless [0]}
}

my $counter = Counter->new;  # overloading survives the assignment

say $counter;

Sie verlieren jedoch die Möglichkeit, den Zähler durch Zuweisung zurückzusetzen. Sie können sub set {$_[0][0] = $_[1]} eine Counter-Methode hinzufügen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top