Почему я не могу сказать print $ somehash {$ var} {fh} "foo"? - PullRequest
8 голосов
/ 13 февраля 2009

У меня есть строка кода в соответствии с:

print $somehash{$var}{fh} "foo";

Хеш содержит дескриптор файла на несколько уровней ниже. Ошибка:

String found where operator expected at test.pl line 10, near "} "foo""

Я могу это исправить, выполнив это:

my $fh = $somehash{$var}{fh};
print $fh "foo";

... но есть ли однострочник?

Ответы [ 3 ]

22 голосов
/ 13 февраля 2009

см. http://perldoc.perl.org/functions/print.html

Обратите внимание, что если вы храните FILEHANDLEs в массиве, или если вы используя любое другое выражение более сложнее, чем скалярная переменная , вам придется использовать блок, возвращающий значение дескриптора файла вместо: ...

Итак, в вашем случае вы бы использовали такой блок:

print { $somehash{$var}{fh} } "foo";
10 голосов
/ 13 февраля 2009

Если у вас есть что-то кроме простого скаляра в качестве дескриптора файла, вам нужно обернуть ссылку, содержащую дескриптор файла, в фигурные скобки, чтобы Perl знал, как проанализировать оператор:

print { $somehash{$var}{fh} } $foo;

Часть Perl Best Practices говорит, что всегда оборачивайте файловые дескрипторы в фигурные скобки именно по этой причине, хотя я не слишком разбираюсь в этом.

Синтаксис странный, потому что print является косвенным методом для объекта дескриптора файла:

method_name Object @arguments;

Возможно, вы видели это в старой школе CGI.pm . Вот два косвенных вызова метода:

use CGI;

my $cgi_object = new CGI 'cat=Buster&bird=nightengale';

my $value = param $cgi_object 'bird';

print "Indirect value is $value\n";

Это почти нормально работает (см. ответ Шверна о неоднозначности ), если объект находится в простом скаляре. Однако, если я добавлю $cgi_object в хеш, я получу ту же синтаксическую ошибку, что и с print. Я могу поставить скобки вокруг доступа к хешу, чтобы все получилось. Продолжая с предыдущим кодом:

my %hash;

$hash{animals}{cgi} = $cgi_object;

# $value = param $hash{animals}{cgi} 'cat';  # syntax error
$value = param { $hash{animals}{cgi} } 'cat';
print "Braced value is $value\n";

Это все немного неуклюже, поэтому просто используйте обозначение стрелки для всего:

my $cgi_object = CGI->new( ... );
$cgi_object->param( ... );

$hash{animals}{cgi}->param( ... );

Вы можете сделать то же самое с файловыми дескрипторами, хотя вы должны использовать модуль IO :: Handle , чтобы все это работало:

use IO::Handle;

STDOUT->print( 'Hello World' );

open my( $fh ), ">", $filename or die ...;
$fh->print( ... );

$hash{animals}{fh} = $fh;

$hash{animals}{fh}->print( ... );
5 голосов
/ 14 февраля 2009

Все ответы верны. Причина, по которой они не допускают использования полного выражения - print FH LIST, - довольно странный синтаксис. Чтобы добавить что-то более сложное, нужно ввести массу неоднозначного синтаксиса. Блок убрал эту двусмысленность.

Чтобы увидеть, к чему ведет это безумие, рассмотрим ужас, который является косвенным синтаксисом объекта.

foo $bar;  # Is that foo($bar) or $bar->foo()?  Good luck!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...