Perlのオブジェクト内関数の間接的な呼び出し  [perl]  [tips]

以下の方法では動かない。

package hoge; 
sub new{
  my $class=shift;
  my $self={'msg2' => 'harahoro','hoge' => \&hoge};
  bless $self,$class;
  return $self;
} 
sub fuga{
  my $self=shift;
  my $msg =shift;
  my $classname=ref $self;
  print "from $classname : hello! $msg\n"; 
} 
sub hoge{
  my $self=shift;
  my $msg = shift;
  print "I am calling fuga\n";
  $self->fuga("hoge : $msg and ". $self->{"msg2"});
} 
1;
package main; 
my $moga=hoge->new;
$moga->{'hoge'}->('self hash'); 

当然、以下も動かない。

package hoge; 
sub new{
  my $class=shift;
  my $self={'msg2' => 'harahoro'};
  bless $self,$class;
  $self->init;
  return $self;
} 
sub init{
  my $self=shift;
  $self->{"hoge"} = \&hoge;
} 
sub fuga{
  my $self=shift;
  my $msg =shift;
  my $classname=ref $self;
  print "from $classname : hello! $msg\n"; 
} 
sub hoge{
  my $self=shift;
  my $msg = shift;
  print "I am calling fuga\n";
  $self->fuga("hoge : $msg and ". $self->{"msg2"});
} 
1;
package main; 
  my $moga=hoge->new;
  $moga->{'hoge'}->('self hash'); 

以下の2点が問題

  • $self->funcのリファレンス取得方法がない
  • \&funcとするとinvocantが渡らない

なので、以下のような解決方法になる。

package hoge;
sub new{
  my $class=shift;
  my $self={'msg2' => 'harahoro'};
  bless $self,$class;
  $self->init;
  return $self;
} 
sub init{
  my $self=shift;
  $self->{"hoge"} = $self->hoge_invocant;
} 
sub fuga{
  my $self=shift;
  my $msg =shift;
  my $classname=ref $self;
  print "from $classname : hello! $msg\n"; 
} 
sub hoge_invocant{
  my $invocant=shift;
  return sub {  hoge($invocant, @_);};
} 
sub hoge{
  my $self=shift;
  my $msg = shift;
  print "I am calling fuga\n";
  $self->fuga("hoge : $msg and ". $self->{"msg2"});
} 
1;
package main; 
my $moga=hoge->new; 
$moga->{'hoge'}->('self hash');

hoge_invocantが

「invocantをレキシカルクロージャとして保持しhogeをinvocantつきで呼び出す無名関数」

を返す。

ここで無名関数を使うべきだということに気付いた。

sub init{
  my $self=shift;
  $self->{"hoge"} = sub {hoge($self, @_);};
}

追記~~

本屋で↑を立ち読みしたら(買え! >> 俺) 載ってた。

同じ結論になってたようなので、買わなくてもいいってことか?

~~追記終わり