2009-01-30 3 views
1

Можно ли определить анонимные подпрограммы в хэш-конструкторе в Perl?Можно ли определить анонимные подпрограммы в хэш-конструкторе в 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'); 

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

+0

В perl они называются хешами, а не ассоциативными массивами. – gpojd

+0

Извините ... Я думаю, что издание книги верблюдов, которую я узнал из названных им ассоциативных массивов. Виноват. –

ответ

11

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

Вам нужно назначить в скаляр:

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

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

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

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

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

Рассмотрите это сообщение. =) –

+2

Конечно, это было бы правильнее, если бы мы назвали эту переменную% hash вместо% array – innaM

+0

@Manni: Хорошая точка. Хотя хэши технически также называются «ассоциативными массивами» на практике, каждый программист Perl, которого я знаю, использует «массив», чтобы иметь в виду исключительно простые массивы, а «хэш» означает хеши. –

6

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

my $array; 
$array = { one => ... }; # not %array = { .. }; 
... 
$array->{one}->('thing'); 
+0

Или просто смените скобки на parens, и массив% может оставаться хешем, а не ссылкой. – kingkongrevenge

2

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

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'); 
3

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

#!/usr/bin/perl -w 

use strict; 

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

+1

Я бы рекомендовал использовать предупреждения over -w, так как первые могут быть отключены в лексической области, когда это необходимо. – friedo

4

Грег Хьюджилл находится на правильном пути. Всегда активируйте прагму 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"; 
} 

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

Смежные вопросы