Program Club

이름이 변수에 포함 된 Perl 서브 루틴을 어떻게 우아하게 호출 할 수 있습니까?

proclub 2021. 1. 5. 08:21
반응형

이름이 변수에 포함 된 Perl 서브 루틴을 어떻게 우아하게 호출 할 수 있습니까?


런타임에 호출하려는 서브 루틴의 이름을 $ action이라는 변수에 유지합니다. 그런 다음 이것을 사용하여 적절한 시간에 해당 하위를 호출합니다.

&{\&{$action}}();

잘 작동합니다. 내가 싫어하는 유일한 점은 추악하고 매번 할 때마다 다음 개발자를 위해 의견을 추가해야한다는 것입니다.

# call the sub by the name of $action

누구든지 이것을하는 더 예쁜 방법을 알고 있습니까?


업데이트 : 여기서 아이디어는 새로운 호출 가능한 서브를 추가 할 때마다 디스패치 테이블을 유지하는 것을 피하는 것이 었습니다. 저는 유일한 개발자이기 때문에 다른 프로그래머가 '규칙'을 따르거나 따르지 않을까 걱정하지 않습니다. 내 편의를 위해 약간의 보안을 희생합니다. 대신 내 디스패치 모듈은 $ action을 확인하여 1) 정의 된 서브 루틴의 이름이고 eval과 함께 실행할 악성 코드가 아닌지, 2) 밑줄로 시작하는 하위 항목을 실행하지 않는지 확인합니다. 이 명명 규칙에 따라 내부 전용 구독자로 표시됩니다.

이 접근 방식에 대한 의견이 있으십니까? 디스패치 테이블에서 서브 루틴을 화이트리스트에 올리는 것은 항상 잊을 수있는 일이며, 제 고객은 "안전하지 못합니다"보다 "작동"측면에서 실수를하려고합니다. (앱 개발에 매우 ​​제한된 시간)


최종 업데이트 : 결국 디스패치 테이블을 결정한 것 같습니다. 이 질문을 읽는 사람이 하나를 없애려고 시도한 적이 있는지, 그리고 어떻게했는지 궁금 하겠지만, 나는 여기에있는 집단적 지혜에 절해야합니다. 모두에게 감사의 말을 전합니다.


변수에 서브 루틴 이름을 저장하고 호출하는 것보다 더 좋은 방법은 서브 루틴 참조의 해시 (또는 디스패치 테이블 이라고도 함)를 사용하는 것 입니다.

my %actions = ( foo => \&foo,
                bar => \&bar,
                baz => sub { print 'baz!' } 
                ... 
              );

그런 다음 쉽게 올바른 전화를 걸 수 있습니다.

$actions{$action}->();

$action해시에서 유효한 키 인지 확인하기 위해 몇 가지 검사를 추가 할 수도 있습니다 .

일반적으로 모든 종류의 문제를 일으키는 기호 참조 (현재 수행중인 작업)는 피해야합니다. 또한 실제 서브 루틴 참조를 사용하면 strict켜진 상태에서 작동 합니다.


단지 &$action()이지만 일반적으로 처음부터 coderef를 사용하거나 디스패처 해시를 사용하는 것이 더 좋습니다. 예를 들면 :

my $disp = {foo => \&some_sub, bar => \&some_other_sub };
$disp->{'foo'}->();

어? 당신은 말할 수 있습니다

    $action->()

예:

    sub f { return 11 }
    $action = 'f';
    print $action->();


    $ perl subfromscalar.pl
    11

같은 구조

    'f'->()     # equivalent to   &f()

또한 작동합니다.


무슨 말인지 잘 모르겠습니다. (나는 이것이 "변수를 변수 이름으로 어떻게 사용할 수 있습니까?"라는 질문의 최근 그룹의 또 다른 질문이라고 생각하지만 아닐 수도 있습니다.)

어떤 경우 든 전체 서브 루틴을 변수 (참조로)에 할당 한 다음 간단하게 호출 할 수 있어야합니다.

# create the $action variable - a reference to the subroutine
my $action = \&preach_it;
# later - perhaps much later - I call it
$action->();

sub preach_it {
    print "Can I get an amen!\n"
}

가장 중요한 것은 함수 이름으로 변수를 사용하려는 이유입니다. 'eval'이면 어떻게 되나요? 사용할 수있는 기능 목록이 있습니까? 아니면 어떤 기능이 될 수 있습니까? 목록이있는 경우-얼마나 걸립니까?

일반적으로 이러한 경우를 처리하는 가장 좋은 방법은 디스패치 테이블을 사용하는 것입니다.

my %dispatch = (
   'addition' => \&some_addition_function,
   'multiplication' => sub { $self->call_method( @_ ) },
);

그리고 그냥 :

$dispatch{ $your_variable }->( 'any', 'args' );

__PACKAGE__->can($action)->(@args);

For more info on can(): http://perldoc.perl.org/UNIVERSAL.html


I do something similar. I split it into two lines to make it slightly more identifiable, but it's not a lot prettier.

my $sub = \&{$action};
$sub->();

I do not know of a more correct or prettier way of doing it. For what it's worth, we have production code that does what you are doing, and it works without having to disable use strict.


Every package in Perl is already a hash table. You can add elements and reference them by the normal hash operations. In general it is not necessary to duplicate the functionality by an additional hash table.

#! /usr/bin/perl -T
use strict;
use warnings;

my $tag = 'HTML';

*::->{$tag} = sub { print '<html>', @_, '</html>', "\n" };

HTML("body1");

*::->{$tag}("body2");

The code prints:

<html>body1</html>
<html>body2</html>

If you need a separate name space, you can define a dedicated package.

See perlmod for further information.


Either use

&{\&{$action}}();

Or use eval to execute the function:

eval("$action()");

I did it in this way:

@func = qw(cpu mem net disk);
foreach my $item (@func){
    $ret .= &$item(1);
}

If it's only in one program, write a function that calls a subroutine using a variable name, and only have to document it/apologize once?


I used this: it works for me.

(\$action)->();

Or you can use 'do', quite similar with previous posts:

$p = do { \&$conn;}; 
$p->();

ReferenceURL : https://stackoverflow.com/questions/1915616/how-can-i-elegantly-call-a-perl-subroutine-whose-name-is-held-in-a-variable

반응형