Perl日記

日々の知ったことのメモなどです。Perlは最近やってないです。

サブルーチンプロトタイプ(&)にしたらサブルーチンを渡せと怒られた

いや渡したんですどね。
サブルーチンプロトタイプ(&)を定義してるサブルーチンに
無名サブルーチンを変数に入れて渡したら怒られたんですよ。

use strict;
use warnings;
use utf8;

sub run(&@) {
  my ($cb, @list) = @_;
  @list = map ++$_, @list;
  $cb->(@list);
}
my @array = 1..10;
my $cb = sub {
  print "@_\n";
};

run $cb, @array;
Type of arg 1 to main::run must be block or sub {} (not private variable) at - line 15, near "@array)"
Execution of - aborted due to compilation errors.
main::runの1個目の引数はブロックまたはsub {}でなければならない。(プライベート変数はだめ)

これ、だめなんだ。初めて知った。
perldoc perlsub見てみた。

An "&" requires an anonymous subroutine, which, if passed as the first argument, does
not require the "sub" keyword or a subsequent comma.

"&"は無名サブルーチンが要るよ、引数の1個目ならsubと後続のカンマは要らないよ。

変数に入れてしまうと「無名サブルーチン」ではなくなるのかー。という解釈でイイノカナー?



OKなのは、

  • 直接無名サブルーチン渡す
  • subを省略したブロックで渡す
  • 定義済みサブルーチンのリファレンスを渡す

の3択みたい。
(3つ目は無名じゃなくない?とも思うが)

# 直接無名サブルーチンを渡す
run(sub { print "@_\n" }, 1..10);
# subを省略したブロックで渡す
run { print "@_\n" } 1..10;
# 定義済みサブルーチンのリファレンスを渡す
sub cb { print "@_\n" }
run(\&cb, 1..10);


どうしても無名サブルーチン入り変数を使うなら、ブロック内で展開しよう。

my $cb = sub { print "@_\n" };
run { $cb->(@_) } 1..10;

ややこしいですかね!