Можно ли определить анонимные подпрограммы в хеш-конструкторе в Perl? - PullRequest
1 голос
/ 31 января 2009

Можно ли определить анонимные подпрограммы в конструкторе хеша в Perl?

Я пытаюсь сделать что-то вроде этого:

my %array = { one   => sub { print "first $_[0]" },
              two   => sub { print "next  $_[0]" },
              three => sub { print "last  $_[0]" }};

$array{$foo}->('thing');

Но это не работает. Кажется, что код запускается и компилируется, но значения в массиве пустые. Если я сделаю это:

my %array;

$array{'one'}   = sub { print "first $_[0]" };
$array{'two'}   = sub { print "next  $_[0]" };
$array{'three'} = sub { print "last  $_[0]" };

$array{$foo}->('thing');

Тогда, кажется, работает нормально. Таким образом, у меня есть обходной путь, но он просто беспокоит меня, и я задавался вопросом, знает ли кто-нибудь, возможно ли это, и если да, то каков синтаксис.

Ответы [ 5 ]

11 голосов
/ 31 января 2009

Похоже, вы неправильно присваиваете хэш. Использование {} создает анонимную ссылку на хеш, которую вы назначаете скаляру. Но вы присваиваете именованный хэш (%array).

Вам необходимо присвоить в скаляр:

my $array = { one   => sub { print "first $_[0]" },
              two   => sub { print "next  $_[0]" },
              three => sub { print "last  $_[0]" }};

$array->{$foo}->('thing');

Или не использовать синтаксис конструктора anon:

my %array = ( one   => sub { print "first $_[0]" },
              two   => sub { print "next  $_[0]" },
              three => sub { print "last  $_[0]" });

$array{$foo}->('thing');
6 голосов
/ 31 января 2009

Это потому, что в первом случае вы создаете хеш-код, а не хеш, то, что вы хотите:

my $array;
$array = { one => ... }; # not %array = { .. };
...
$array->{one}->('thing');
4 голосов
/ 31 января 2009

Грег Хьюгилл находится на правильном пути. Всегда включайте прагму strict. Кроме того, всегда включайте предупреждения - но я не рекомендую использовать ключ -w в вашем коде.

Вместо этого воспользуйтесь use warnings прагмой. Таким образом, вы можете выборочно отключать определенные группы предупреждений в лексически ограниченных областях вашего кода.

Например:

use strict;
use warnings;

foo('bar');
foo();

sub foo {
    no warnings 'uninitialized';

    my $foo = shift || 'DEFAULT';

    print "Foo is $foo\n";
} 

Последовательное использование прагм строго и предупреждений сэкономит вам часы и часы времени.

3 голосов
/ 31 января 2009

Я потратил около двух часов, пытаясь отследить эту точную проблему скобок против скобок в сценарии не так давно. Если вы используете переключатель -w для Perl, вы получите предупреждение «Ссылка найдена там, где ожидается список четного размера», который, по крайней мере, дает подсказку, где искать. Сегодня все сценарии Perl должны начинаться с:

#!/usr/bin/perl -w

use strict;

Ваша жизнь в Perl будет неизмеримо менее расстраивающей.

2 голосов
/ 31 января 2009

Это должны быть круглые скобки, а не фигурные скобки:

my %array = ( one   => sub { print "first $_[0]" },
              two   => sub { print "next  $_[0]" },
              three => sub { print "last  $_[0]" }});

'{a => 1, b => 2}' создает ссылку на хеш. Таким образом, следующее также будет работать:

my $array = { one   => sub { print "first $_[0]" },
              two   => sub { print "next  $_[0]" },
              three => sub { print "last  $_[0]" }};

$array->{one}->('thing');
...