2010-08-04 3 views
0

우리는 더 이상 신경 쓸 필요가 없도록 commit() 및 rollback()을 자동으로 지원하는 API를 빌드하려고합니다. 조사한 결과 eval {}을 사용하는 것이 좋습니다.Perl에서 함수 배열 사용 정보

eval {} 무엇을 해야할지 알고 싶다면 API를 입력하지 않고도 foreach과 함께 실행할 수있는 함수 배열을 API에 제공 할 생각이었습니다. 그러나이 기능은 다른 패키지에있을 수 있습니다.

날 예제를 통해 명확히하자

sub handler { 
    use OSA::SQL; 
    use OSA::ourAPI; 
    my @functions =(); 
    push(@functions, OSA::SQL->add_page($date, $stuff, $foo, $bar)); 
    my $API = OSA::ourAPI->connect(); 
    $API->exec_multi(@functions); 
} 

질문입니다 : 가능 ourAPI 더 use OSA::SQL이없는 경우에도, OSA::ourAPI의 내부 @functions의 기능을 수행하는 것입니다. 그렇지 않다면 포인터가 메모리 내부의 알려진 함수를 가리 키도록 배열 대신 배열 참조를 사용하면 가능합니까?

참고 : 더 복잡한 최종 버전을 기반으로하고 싶다는 기본 아이디어입니다.

+0

"OSA :: ourAPI 내부에서 주어진 함수를 실행하십시오."라는 말을 이해하지 못합니다. – cjm

+0

나는 명확하게하기 위해 나의 질문을 편집했다. @functions 내부의 함수는 내가 말하는 것들이다. – Mike

+0

'eval'은 거의 쓸모가 없습니다 ... 메소드 안에'use' 문을 두는 것은 메소드가 실행될 때까지 실행을 지연시키지 않습니다. 파일이 파싱 될 때 즉시 실행됩니다. – Ether

답변

4

  • 당신은 당신의 배열 함수 포인터를 추가하지 않습니다. add_page() 서브 루틴 호출의 반환 값을 추가하고 있습니다.

    가. [\&OSA::SQL::add_page, @argument_values] 형태의 arrayrefs를 저장해야합니다. 즉, 서브 루틴 (정적이라고 함)에 대한 실제 참조를 전달해야합니다. 다음 exec_multi은 (는 오전 4시은 여기로 100 % 정확하지 않을 수 있습니다 구문)

     
    sub exec_multi { 
        my ($class, $funcs)= @_; 
        foreach my $f (@$funcs) { 
         my ($func, @args) = @$f; 
         my $res = &$func(@args); 
         print "RES:$res\n"; 
        } 
    } 
    

    그냥 다시 반복,이 정적 버전 (OSA::SQL::add_page), 예를 들어, 개별 서브 우퍼를 호출 같은 것을 할 것입니다 패키지 이름을 첫 번째 매개 변수로 전달하지 않고 OSA::SQL->add_page 클래스 호출로 사용합니다. 후자를 원한다면 다음 해결책을보십시오.


    B. 당신이 (첫 번째 매개 변수로 클래스 이름 즉, 귀하의 예제처럼) 클래스 컨텍스트에서 잠수정을 호출 할 경우, 당신은 코멘트에 ysth의 제안을 사용할 수 있습니다.

    [sub { OSA::SQL->add_page(@argument_values) }] 형식의 배열 설명 배열을 저장해야합니다 (즉, @functions). 이는 필요한 것을 호출하는 서브 루틴에 대한 참조를 전달한다는 의미입니다. 다음 exec_multi는

     
    sub exec_multi { 
        my ($class, $funcs)= @_; 
        foreach my $f (@$funcs) { 
         my ($func) = @$f; 
         my $res = &$func(); 
         print "RES:$res\n"; 
        } 
    } 
    

    C. (는 오전 4시은 여기로 100 % 정확하지 않을 수 있습니다 구문) 같은 것을 할 것입니다[ "OSA::SQL", "add_page", @argument_values] 형태의 arrayrefs 배열을 (@functions에) 저장해야합니다. 이는 패키지와 함수 이름을 전달한다는 것을 의미합니다. 내가 제대로 질문을 이해하면 다음 exec_multi는 당신이 필요하지 않습니다,

     
    my ($package, $sub, @args) = @{ $functions[$i] }; 
    no strict 'refs'; 
    $package->$sub(@args); 
    use strict 'refs'; 
    

  • (는 오전 4시은 여기로 100 % 정확하지 않을 수 있습니다 구문) 같은 것을 할 것입니다 우리의 API가 OSA :: SQL을 사용하는지 여부에 대해서는 걱정하지 마십시오. 주 코드가 이미 그것을 수입하기 때문입니다.

    그러나 - # 1B에서 - 각 배열 참조의 첫 번째 요소로 exec_multi에 패키지 목록을 전달할 것이므로 exec_multi에서 "require $package; $package->import();"을 수행 할 수 있습니다. 그러나 다시 한번 말하지만, 여러분의 처리기 호출이 이미 필요하고 각 패키지를로드했다면 완전히 불필요합니다. 그리고 바로하기 위해서는 매개 변수 목록을 import()으로 전달해야합니다. 그러나 왜? :)

+2

'use $ package;'는 유효하지 않습니다. 모듈 이름을 .pm 파일의 상대 경로 이름으로 변환 한 다음'require'를 사용할 수 있습니다. @functions가 coderefs 만 저장하는 것이 더 좋습니다 :'push @functions, sub {OSA :: SQL-> add_page ($ date, $ stuff, $ foo, $ bar)}; ' – ysth

+0

@ysth - LOL .. . yah, 나는 게시 한 직후 두 가지 모두를 깨달았다. 두 번째 솔루션에 대한 나의 해결책은 약간 다릅니다. – DVK