Como posso chamar métodos em uma variável vinculado?
Pergunta
Eu apenas comecei a aprender sobre laço . Eu tenho uma classe chamada Fazer a ligação que eu gostaria de fazer o seguinte:
- se buscado, retornar o endereço do link
- se armazenado, armazenar o novo endereço
- ser capaz de chamar métodos nele
Até agora, o meu código é:
package Link;
sub FETCH {
my $this = shift;
return $this->{"site"};
}
sub STORE {
my ($self,$site) = @_;
$self->{"site"} = $site;
}
sub print_method {
my $self = shift;
print $self->{"site"};
}
sub TIESCALAR {
my $class = shift;
my $link = shift;
my $this = {};
bless($this,$class);
$this->{"site"} = $link;
return $this;
}
1;
E o código que estou usando para verificar a funcionalidade é:
use Link;
tie my $var,"Link","http://somesite.com";
$var->print_method;
Quando correu, o script terminará com o seguinte erro: Não é possível chamar o método "print_method" sem um pacote ou referência de objeto no tietest.pl linha 4. .
Se eu entendo a sua mensagem corretamente, $var->print_method
resolve alguma corda sobre a qual o método print_method
é chamado. Como eu poderia beneficiar de empate, mas também usar a variável como um objeto?
EDIT: depois de experimentar um pouco, eu descobri que se eu voltar $ self em buscar, eu posso chamar os métodos, no entanto, buscar não retornará o endereço
.EDIT 2: os monges Perl fornecido me a solução: amarrado . amarrado irá retornar uma referência para o objeto variável.
Ao combinar amarrado com meus métodos, eu posso realizar tudo o que eu queria.
Solução
Tie é a ferramenta errada para este trabalho. Você usa laços quando você quer a mesma interface como tipos de dados normais, mas quero personalizar a forma como as operações de fazer o seu trabalho. Desde que você deseja acessar e armazenar uma string como um escalar já faz, empate não faz nada para você.
Parece que você deseja que o URI módulo, ou uma subclasse do mesmo, e talvez alguma sobrecarga.
Se você realmente precisar fazer isso, você precisa usar a variável direita. A amarrar conecta-se a variável que você especificar para a classe que você especificar, mas ainda de um escalar normal (e não uma referência). Você tem que usar o objeto que ele retorna, se você quiser chamar métodos:
my $secret_object = tie my($normal_scalar), 'Tie::Class', @args;
$secret_object->print_method;
Você também pode obter o objeto segredo se você só tem a escalar amarrado:
my $secret_object = tied $normal_scalar;
Eu tenho um capítulo inteiro sobre empate na Mastering Perl .
Outras dicas
Sugiro fazer um objeto normal de Perl e depois sobrecarga ing stringification. Você perde a capacidade de armazenar um valor através da atribuição, mas mantêm a capacidade de obter o valor pelo impressão do objeto. Uma vez que você começar a querer chamar métodos diretamente, um objeto é provavelmente o que você quer.
package Link;
use strict;
use Carp;
use overload
(
'""' => sub { shift->site },
fallback => 1,
);
sub new
{
my $class = shift;
my $self = bless {}, $class;
if(@_)
{
if(@_ == 1)
{
$self->{'site'} = shift;
}
else { croak "$class->new() expects a single URL argument" }
}
return $self;
}
sub site
{
my $self = shift;
$self->{'site'} = shift if(@_);
return $self->{'site'};
}
sub print_method
{
my $self = shift;
print $self->site, "\n";
}
1;
Exemplo de utilização:
use Link;
my $link = Link->new('http://somesite.com');
print $link, "\n"; # http://somesite.com
$link->print_method; # http://somesite.com
Se você realmente quer atribuição ao trabalho também, você pode combinar um objeto normal com stringification sobrecarregado (Link
, acima) com tie
:
package LinkTie;
use strict;
use Link;
sub FETCH
{
my $this = shift;
return $this->{'link'};
}
sub STORE
{
my($self, $site) = @_;
$self->{'link'}->site($site);
return $site;
}
# XXX: You could generalize this delegation with Class::Delegation or similar
sub print_method
{
my $self = shift;
print $self->{'link'}->print_method;
}
sub TIESCALAR
{
my $class = shift;
my $self = bless {}, $class;
$self->{'link'} = Link->new(@_);
return $self;
}
1;
Exemplo de utilização:
tie my $link,'LinkTie','http://somesite.com';
print $link, "\n"; # http://somesite.com
$link->print_method; # http://somesite.com
$link = 'http://othersite.com';
print $link, "\n"; # http://othersite.com
$link->print_method; # http://othersite.com
Isso tudo é bastante hediondo e um longo caminho a percorrer apenas para obter a capacidade duvidosa para atribuir a algo que você também pode chamar métodos e também imprimir como está. Um objeto URI padrão com stringification é provavelmente a melhor aposta.