Pergunta

Se eu tivesse uma classe escalar vinculada simples que aumentasse toda vez que fosse lida, eu poderia fazer assim:

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;

Porém para criar uma variável de contador eu tenho que usar tie.Eu poderia criar um contador e exportá-lo.Mas o que eu realmente quero fazer é fazer com que pareça OO.Parece que eu poderia criar um new método como este:

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

  tie $counter, $class;

  return $counter;
}

então, no meu script principal, obtenha dois contadores fazendo:

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

Presumo que isso não funcione porque um empate não sobrevive a uma cópia (li isso nos documentos em algum lugar). Simplesmente não há maneira de fazer isso?

Nota.Eu sei que é apenas uma questão de estilo, mas pareceria mais correto aos olhos.

Foi útil?

Solução

A magia do empate não é realizada na atribuição porque se aplica à própria variável, não ao valor que ela contém.Você tem poucas opções:

Retornando uma referência:

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

my $counter = Counter->new;

say $$counter;

Atribuindo a um globo:

our ($counter);

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

say $counter;

Ou você pode passar a variável para o construtor:

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

Counter->new(my $counter);

say $counter;

Você pode até criar um construtor que funcione com os dois métodos:

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

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

Counter->new(my $lexical);

Nos dois últimos exemplos, tie é passado $_[0] diretamente.A razão para isso é que os elementos @_ são aliases para a lista de argumentos, então funciona como se você tivesse digitado o my $counter no tie linha.


E, finalmente, embora seu exemplo seja muito claro e siga as melhores práticas, no espírito do TIMTOWTDI, você poderia escrever toda a sua aula assim:

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

Uma última coisa a mencionar.Embora sua pergunta seja sobre variáveis ​​vinculadas, você também pode usar a sobrecarga para conseguir isso:

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

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

say $counter;

Mas você perde a capacidade de zerar o contador por meio de atribuição.Você poderia adicionar um sub set {$_[0][0] = $_[1]} método para Counter.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top