2010-05-22 5 views
1

가능한 중복 :
Is it possible for a Perl subroutine to force its caller to return?Perl이 호출자에게 어떻게 반환 할 수 있습니까?

내가 특정 조건에서 반환 할 호출을 유발하는 서브 루틴을 쓰고 싶어요. 이것은 함수에 대한 입력을 검증하는 지름길로 사용하기위한 것입니다. 내가 지금까지있는 것은 :

sub needs($$) { 
    my ($condition, $message) = @_; 

    if (not $condition) { 
     print "$message\n"; 
     # would like to return from the *parent* here 
    } 

    return $condition; 
} 

sub run_find { 
    my $arg = shift @_; 
    needs $arg, "arg required" or return; 
    needs exists $lang{$arg}, "No such language: $arg" or return; 

    # etc. 
} 

needs의 호출에서 반환의 장점은 다음 run_find와 유사한 기능 내부의 반복적 인 or return를 작성하지 않도록하는 것입니다.

+0

당신이 그것을 썼을 때'need'는 항상'$ condition'을 반환 할 것입니다. 그렇지 않습니까? – Zaid

답변

4

난 당신이 여기에 잘못된 일에 국한 있다고 생각 아래 있듯이

sub well_defined { 

    my $arg = shift; 
    $arg or warn "arg required" and return 0; 
    exists $lang{$arg} or warn "no such language: $arg" and return 0; 
    return 1; 
} 

는 부울 - 억양 동작을 할 수 있습니다. 나는 Data :: Constraint, Brick, 등등을 가지고 이런 종류의 일을하고 이것에 대해 Mastering Perl에서 이야기한다. Perl이 가지고있는 프로그램의 구조와 동적 인 기능에 대해 약간의 영리함과 생각으로, 당신은 그러한 연대적이고 절차적인 접근이 필요하지 않습니다.

그러나 먼저 알아야 할 사항은 해당 호출 서브 루틴에서 실제로 알고 자하는 것입니다. 예 또는 아니오를 알고 싶다면 꽤 쉽습니다.

needs의 문제점은 모든 조건에 대해 한 번 호출하면 프로그램 흐름을 제어하기 위해 needs을 사용해야한다는 것입니다. 그것이 잘못된 길입니다. needs은 답변을 드릴 수있는 곳입니다. 프로그램 상태를 변경하지 않는 것이 임무입니다. needs이 false를 반환하더라도 다른 호출 서브 루틴이 계속되기를 원하기 때문에 잘못 사용할 경우 유용하지 않게됩니다. 한 번만 부르면 한 번 되돌려 야합니다. 호출 서브 루틴은 반환 값을 사용하여 수행 할 작업을 결정합니다.

기본 구조에는 needs에 전달하는 테이블이 포함됩니다. 이것은 귀하의 유효성 확인 프로파일입니다.

요구 사항이 무엇이든간에 테이블을 구성하십시오.

sub needs($$) { 
    my ($table) = @_; 

    foreach $test (@$table) { 
     my($sub, $message) = @$test; 
     unless($sub->(...)) { 
      print $message; 
      return 
      } 
     } 

    return 1; 
    } 

자,이 방법과 함께 정말 멋진 일이 당신이 미리 표를 알 필요가 없다는 것입니다 : needs에서 당신은 단지 테이블을 처리합니다. 당신은 설정이나 다른 방법으로부터 그것을 끌어낼 수 있습니다. 이는 테이블을 동적으로 변경할 수 있음을 의미합니다. 이제 코드가 상당히 축소됩니다.

 
sub run_find { 
    my $arg = shift @_; 
    return unless needs($validators{run_find}); 
    ... 
    } 

이 작업을 계속 진행하십시오. In Perl 마스터하기 코드에서 코드를 완전히 제거하고 구성 파일로 옮기는 몇 가지 솔루션을 보여줍니다. 즉, 코드를 변경하지 않고 비즈니스 규칙을 변경할 수 있습니다.

동일한 문자 시퀀스를 입력 할 때 거의 언제든지 잘못 생각한 것입니다.:)

+0

+ 1 테이블 아이디어가 환상적이라고 말해야합니다. – Zaid

+0

그래, 테이블 아이디어가 내 요구를 충족시킵니다. 그것은 범위에 이상한 엉망이 필요하지 않지만, 그것은 여전히 ​​자세한 표시를 줄입니다. –

4

예외 처리를 다시 발명하는 것처럼 들립니다.

needs 함수는 마술처럼 부모를 추론해서는 안되며 부모의 제어 흐름을 방해해서는 안됩니다. 이는 나쁜 매너입니다. 호출 체인에 추가 기능을 추가하고 두 개 또는 세 개의 함수로 돌아 가야 할 경우 어떻게해야합니까? 어떻게 이것을 프로그래밍 방식으로 결정할 수 있습니까? 발신자가 자신의 기능이 일찍 돌아올 것으로 기대합니까? 당신이 버그를 피하려는 경우 적어도 놀라움의 원칙을 따라야합니다 - 그게 처리하는 방법을 결정 발신자 문제가 있음을 나타 내기 위해 예외를 사용하고 것을 의미 :

use Carp; 
use Try::Tiny; 

sub run_find { 
    my $arg = shift; 
    defined $arg or croak "arg required"; 
    exists $lang{$arg} or croak "no such language: $arg"; 

    ... 
} 

sub parent { 
    try { run_find('foo') } 
    catch { print [email protected]; } 
} 

의 내부 코드를 try 블록은 특별합니다. 어떤 것이 죽으면 예외는 캐치되어 [email protected]에 저장됩니다. 이 경우 catch 블록이 실행되고 오류가 STDOUT으로 인쇄되고 제어 흐름이 정상적으로 계속됩니다.

면책 조항 : Perl의 예외 처리는 고통입니다. 나는 많은 일반적인 잡았다 (그리고 친숙한 try/catch 의미론을 제공한다)와 Exception::Class을 보호하기 위해 예외 객체를 빠르게 만들어서 Perl의 오류와 자신의 오류를 구별 할 수있는 Try::Tiny을 권장한다.

인수의 유효성을 확인하려면 Params::Validate과 같은 CPAN 모듈을 사용하는 것이 더 쉽습니다.

+0

"catch {print $ @;}"대신 "catch {print $ _;}"라고 쓰면 오류 메시지 만 표시됩니다. –

+0

문제는 run_find 호출자가 내 컨트롤 외부 모듈입니다 (Term : : 쉘, 당신이 관심 있다면), 그리고 그 호출자는'eval'에서 내 호출을 감싸지 않습니다. 이후로 전체 프로세스를 중단하고 싶지 않으므로 정상적으로 run_find를 종료하고 다른 방법으로 오류를 처리해야합니다. –

1

당신은 kinopiko에 의해 유사한 최근의 문제를보고 할 수 있습니다 : 는 Is it possible for a Perl subroutine to force its caller to return?

그에 대한 요약은 다음과 같습니다 가장 좋은 방법은 시도 :: 작은, 등, (/ 평가 다이 예외를 사용하는 것입니다 ...). 너는 또한 GOTO를 사용하고 가능하게 Continuation :: Escape

0

이런 식으로 일을하는 것은 의미가 없다; 아이러니하게도 나중에는 needs이 필요하지 않습니다.

여기 왜 있습니다.

  • run_find이 잘못 작성되었습니다. 첫 번째 조건이 참이라면, return이 이미 적용될 것이기 때문에 두 번째 조건을 테스트하지 않을 것입니다.
  • warndie 함수는 인쇄 및/또는 종료 동작을 제공합니다.여기

당신이 당신의 인수가 실패 할 경우 실행을 종료하기를 원한다면 나는 당신의 run_find 서브를 작성합니다 방법 (well_defined에 이름) :

sub well_defined { 

    my $arg = shift; 
    $arg or die "arg required"; 
    exists $lang{$arg} or die "no such language: $arg"; 
    return 1; 
} 

가에 return 0warn 할 수있는 방법이 있어야합니다 같은 시간이지만 조금 더 놀아야 할 것입니다. 그들은 ( well_defined로 변경)하는 경우

run_findreturn 0 및 조건이 충족되지 않을 경우 해당 warn 메시지 및 return 1 쓸 수 있습니다.

perform_calculation $arg if well_defined $arg; # executes only if well-defined 
+0

''그런 언어를 경고하지 마라 ', return 0;'? – Ether

+0

@Ether : Perl의 한 줄짜리에서 당신의 제안을 시도했지만 제대로 경고하지 않았다 :'perl -e "sub rf {$ arg = shift; $ arg 또는 warn qq (arg가 없다), return 0; return 1;} qq (Yes)이면 rf; ". ','를'와'로 바꾸면 작동합니다. – Zaid

+0

아 예, 나는'warn'이리스트를 취하는 것을 잊었습니다. 그래서 우리는 arg를 끝내는 곳을 표시하기 위해 괄호를 추가하지 않는 한 모든 것을 중얼 거립니다.'warn ("그런 언어가 없다), return 0; – Ether

관련 문제