2013-03-28 7 views
0

Мне нужно использовать один и тот же дескриптор файла в нескольких perl-модулях. Вот мой пример a.plглобальный дескриптор файла

#!/usr/bin/perl -w 

our $OUT_FILE_HANDLE; 

require b; 

open($OUT_FILE_HANDLE, ">./a.log"); 
print $OUT_FILE_HANDLE "text1\n"; 

b::f($OUT_FILE_HANDLE); // this works 

b.pm

package b; 

sub f($) { 
    my $a = shift; 
    print $a "text2\n"; // get error here 
} 

f($main::OUT_FILE_HANDLE); 
1; 

Я получаю сообщение об ошибке «Не удается использовать неопределенное значение в качестве опорного символа»

Если я использую обрабатывать в b.pm напрямую (без передачи его в качестве аргумента функции), он работает нормально

b.pm

package b; 

sub f() { 
    print $main::OUT_FILE_HANDLE "text2\n"; // this works 
} 

f(); 
1; 
+0

Вы знаете, что есть основной модуль с именем 'B', не так ли? Вы должны избегать однобуквенных имен модулей, даже когда проверяете ситуацию. Или, возможно, * особенно * при тестировании. – TLP

ответ

9

Ваш пример не выполнен из-за порядка выполнения: all of b.pm is executed when you require b;. Таким образом, вы пытаетесь использовать дескриптор файла до его открытия.

Как правило, модули должны выполнять только функции, которые могут быть вызваны. При выполнении модуля должны выполняться только операции инициализации.

В этом случае лучшим дизайном будет использование дескриптора файла lexical и передать его любой функции, которая в ней нуждается. Не используйте глобальный.

open(my $OUT_FILE_HANDLE, '>', './a.log') or die "Ouch: $!"; 
print $OUT_FILE_HANDLE "text1\n"; 

b::f($OUT_FILE_HANDLE); 

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

Наконец, вы почти никогда не должны использовать прототипы подпрограмм в Perl. Просто опустите прототип, если вы не знаете все о прототипах Perl и есть очень веские причины, чтобы использовать их:

sub f { 
-1

Может двигаться «наш $ OUT_FILE_HANDLE;» внутри вашего пакета b.pm.

+0

Неправильное использование. 'наш' вообще не нужен при доступе к переменной через' $ package_name :: variable'. – 2013-03-28 13:15:26

+0

Hi dan1111. Ответ на этот вопрос правильный. Возник вопрос: «Невозможно использовать неопределенное значение в качестве ссылки на символ». Вопрос не касался ее домашней работы, считал, что ваш ответ прав. –

+0

№ «Невозможно использовать неопределенное значение в качестве ссылки на символ» ** не ** вызвано отсутствием в нашем документе декларации 'our'. Модуль может * видеть * переменную просто отлично; он не определен, поскольку переменная не была настроена на что-либо в точке, в которой выполняется код модуля. Добавление 'our' не изменило бы этого. Это позволит вам использовать '$ variable', а не' $ package_name :: variable' для доступа к переменной. – 2013-04-02 07:35:31

1

B - плохое имя для модуля, поскольку это Perl core module. Переименуйте его с помощью BB (например). Кроме того, комментарии Perl используют '#', а не '//'. Это мой модифицированный код (который работает отлично):

main.pl

use BB; 

our $OUT_FILE_HANDLE; 
open($OUT_FILE_HANDLE, ">", "./a.log") or die $!; 
print $OUT_FILE_HANDLE "text1\n"; 
BB::f($OUT_FILE_HANDLE); 

BB.pm

package BB; 

sub f { 
    my $a = shift; 
    print $a "text2\n"; 
} 
1; 
+0

Я использую только B. В моем сценарии я использовал другие имена, но я все еще получаю ошибку – Gayane

+0

вы попробовали мой код? он работает ... –

+0

Да, спасибо – Gayane

3

Есть много проблем с вашим кодом.

  • Всегдаuse strict и use warnings в верхней части вашей программы или сразу после package заявления

  • Использование CamelCase для имен пакетов и snake_case для локальных идентификаторов.Люди, знакомые с Perl, будут благодарны вам

  • Используйте что-нибудь описательное для всех ваших идентификаторов. В частности, существует основной пакет под названием B (Perl-компилятор Backend), так что это не будет делать

  • Никогда ожидать дочерней модуль для доступа к данным из main пакета. Поток должен быть строго снизу вверх

  • Никогда использовать прототипы для ваших подпрограмм. Perl отличается от других языков в этом отношении, а прототипы делают пару очень особенных вещей. Если вы не знаете, что это такое, вы, конечно, не должны использовать прототипы.

  • Не используйте require, если вы не знаете, что он делает. Вы почти наверняка хотите use

  • Используйте форму трехпараметрическую open и всегда проверить, была ли она преуспела. Если open failes то вы должны die со строкой, включая $! сказать почему он не

Основная причина ваш код не работает, как вы ожидаете, что requireuse) заявления будут выполнять любые исполняемые операторы во вторичном модуле на момент их включения. Обычно такие модули содержат только определения и объявления для использования в вызывающем коде, и вы должны быть очень осторожны, если вы включаете исполняемый код, потому что, как вы видели, это может вызвать проблемы с отсутствием зависимостей.

Вот рабочая версия кода

main.pl

use strict; 
use warnings; 

use BB; 

open my $fh, '>', 'a.log' or die $!; 
print $fh "text1\n"; 

BB::f($fh); 

BB.pm

package BB; 

use strict; 
use warnings; 

sub f { 
    my ($a) = @_; 
    print $a "text2\n"; 
} 

1; 

выход (для a.log)

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