2013-08-31 3 views
1

Имеет ли первый пример с typeglobs недостатки по сравнению со вторым примером?Наследование функции с помощью типовglobs

package Some::Module::Win32; 
use strict; 
use 5.10.0; 

use Exporter 'import'; 
our @EXPORT_OK = qw(public); 

use Some::Module; 

*_func_one = \&Some::Module::_func_one; 
*_func_two = \&Some::Module::_func_two; 
*_func_three = \&Some::Module::_func_three; 

sub public { 
    my $s = _func_one(); 
    for my $i (0 .. $s) { 
     say _func_two($i); 
    } 
    say _func_three($s); 
} 

1; 

package Some::Module::Win32; 
use strict; 
use 5.10.0; 

use Exporter 'import'; 
our @EXPORT_OK = qw(public); 

use Some::Module; 

sub public { 
    my $s = Some::Module::_func_one(); 
    for my $i (0 .. $s) { 
     say Some::Module::_func_two($i); 
    } 
    say Some::Module::_func_three($s); 
} 

1; 

ответ

3

Вашего первый пример вид показывает, как Exporter работы: назначая тип-глоб. Но есть важная разница: , когда функции импортируются. Это в основном важно, когда подпрограмма имеет прототип. Прототипы должны быть известны во время обработки и поэтому должны быть известны в фазе BEGIN. use - который обычно называет import на использованном пакете - обрабатывается в фазе BEGIN.

Вы также должны понимать, что в первом примере, пользователи вашего кода теперь Some::Module::Win32::_func_one() тогда это не возможно в 2-ом примере (если Some::Module_func_one экспорта.

Вот версия, которая импортирует функцию правильная фаза:

package Some::Module::Win32; 
use strict; 
use 5.10.1; # because `parent` comes with 10.1 

use parent 'Exporter'; # optimal way to inherit the `import`. 
our @EXPORT_OK = qw(public); 

use Some::Module; 

BEGIN { 
    *_func_one = \&Some::Module::_func_one; 
    *_func_two = \&Some::Module::_func_two; 
    *_func_three = \&Some::Module::_func_three; 
} 

sub public { 
    my $s = _func_one(); 
    for my $i (0 .. $s) { 
     say _func_two($i); 
    } 
    say _func_three($s); 
} 

1; 

И если вы хотите, вы можете использовать модуль как namespace::autoclean, чтобы удалить инородный импорт из таблицы символов, как только они больше не нужны вам

.

Другой стратегией было бы поставить coderefs в лексические переменные. Однако синтаксис немного некрасиво, и любые прототипы полностью проигнорировано:

package Some::Module::Win32; 
use strict; 
use 5.10.1; 

use parent 'Exporter'; 
our @EXPORT_OK = qw(public); 

use Some::Module; 

my $func_one = \&Some::Module::_func_one; 
my $func_two = \&Some::Module::_func_two; 
my $func_three = \&Some::Module::_func_three; 

sub public { 
    my $s = $func_one->(); 
    for my $i (0 .. $s) { 
     say $func_two->($i); 
    } 
    say $func_three->($s); 
} 

1; 

Это не касается таблицы символов, и, следовательно, может рассматриваться как очень «чистый» решение.

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

  • прототипы работают правильно
  • очень читаемый (если полное имя функции не является безумно долго, как Marpa::R2::Inner::Scanless::G::SYMBOL_IDS_BY_EVENT_NAME_AND_TYPE)
  • однозначна
  • нет имен загрязнения
+0

Очевидно ничего технического, чтобы добавить, но +1 для читаемых. Храните умный код, когда он вам действительно нужен. –