2010-06-14 2 views
6

Иногда мне нужна полезная функция полезности, например List::Util::max в середине большой программы, которая делает много вещей. Так что, если яЛексически импортировать полезные функции в большой скрипт

use List::Util 'max'; 

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

Так я думал о попытке другой шаблон, вместо этого:

use List::Util(); 

# a whole bunch of stuff later... 
sub blah { 
    List::Util->import('max'); 
    $blah = max @foobar; 
    ... 
} 

Есть две проблемы с этим, хотя. Во-первых, он не автоматически unimport в конце блока (drat.) Мне пришлось бы отменить все с помощью unimport.

Другая проблема заключается в том, что, по-видимому, прототипы не применяются правильно, поэтому я должен сказать max(@foobar) вместо более красивой версии без буклета.

Есть ли простой способ временного импорта символов для блока, который автоматически удалил бы их в конце блока и который бы также правильно обрабатывал прототипы?

ответ

1

Вы можете локализовать запись таблицы символов:

use List::Util(); 

@y = qw(1 3 5 -9 4); 

sub max { # return maximum *absolute value* of list 
    my $max = abs(shift); 
    $max<abs($_) && ($max=$abs($_)) for @_; 
    return $max; 
} 

sub max2 { 
    local *max = *List::Util::max; 
    return max(@_); 
} 

print "My max:   ", max(@y), "\n"; # ==> 9 
print "List::Util::max ", max2(@y), "\n"; # ==> 5 
+3

Это приведет к тонким ошибкам, если какой-либо 'max' имеет прототип, так как эффект от него сжигается во время компиляции. В 'max2' используется прототип из' main :: max', а не из списка List :: Util :: max'. Полезно, вы должны получить предупреждение о несоответствии прототипа при назначении. –

+0

@ Эрик Стром - Хорошая мысль, что сосать. Используйте имя подпрограммы 'local' с осторожностью. – mob

4

Просто сделай это, это намного лучше и чище:

package Foo; 
use strict; use warnings; 
use List::Util 'max'; 
use namespace::autoclean; 

# your method definitions here... 

namespace::autoclean будет «unimport» символ после компиляции цикла программ пакета выполняется. Вызов к нему в вашем методе будет по-прежнему работать, но у вас нет загрязнения пространства имен (удаляется символ *Foo::max), и вызов $obj->max() не удастся.

В качестве альтернативы, вы можете взглянуть на Lexical::Import (я ничего об этом не знаю, птица упомянула об этом).

+0

В то время как 'имен :: autoclean' является Spiffy, она не решает главную проблему, которая является то, что' max' еще есть во всем пакете, а не ограничивается одним блоком, который это то, чего я действительно пытаюсь достичь. Я хочу, чтобы мои функции полезности вели себя как лексические переменные. – friedo

+0

@friedo: почему проблема в том, что 'max' доступен для всего пакета? Если проблема связана с загрязнением пространства имен, то об этом и заботится этот модуль. – Ether

+0

Возможно, мне нужен другой * 'max' где-то еще в пакете. – friedo

1

perlfunc означает, что no MODULE должны делать то, что вы хотите:

sub blah { 
    use List::Util qw(max); 
    say max @foobar; 
    no List::Util; 
} 

, но это не работает - по крайней мере, не для списка: : Util. Я считаю, что ему нужно будет определить метод unimport. Даже тогда я не уверен, что у вас может быть голый max в вашем модуле, который вызывает разные определения.

+0

Не будут ли строки 'use' и' no' выполняться в другое (более раннее) время, чем остальные определения sub? – Ether

+0

И «использование», и «нет» происходят во время компиляции; они будут исполняться при компиляции 'blah'. –

2

Если вы используете только max в одной подпрограмме, я бы не импортировал ее в пространство имен вообще. Мое решение является

use List::Util; 
sub blah { 
    print List::Util::max(@list); 
} 
+0

Это все еще отличает прототипы, поэтому вы можете оставить скобки: print List :: Util :: max @list; – dwarring

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