2011-07-05 3 views
8

펄 foreach 루프는

#!/usr/bin/env perl 

use strict; 
use warnings; 

my @foo = (0,1,2,3,4); 

foreach my $i (@foo) { 
    sub printer { 
     my $blah = shift @_; 
     print "$blah-$i\n"; 
    } 

    printer("test"); 
} 

내가 무엇을 기대하지 않는 다음 코드를 규칙.

정확히 어떤 현상이 발생합니까? (나는 그것이 인쇄 기대 "테스트-0 \ ntest-1 \ ntest-2 \ ntest-3 \ ntest-4 \ n")

답변

19

문제는 sub name {...} 구조가 그렇게 중첩 될 수 없다는 것입니다 루프는 for입니다.

이유는 sub name {...}이 실제로는 BEGIN {*name = sub {...}}을 의미하고 시작 블록이 구문 분석되는 즉시 실행되기 때문입니다. 컴파일과 서브 루틴의 변수 바인딩은 for 루프가 실행되기 전에 컴파일 타임에 발생합니다.

#!/usr/bin/env perl 

use strict; 
use warnings; 

my @foo = (0,1,2,3,4); 

foreach my $i (@foo) { 
    my $printer = sub { 
     my $blah = shift @_; 
     print "$blah-$i\n"; 
    }; 

    $printer->("test"); 
} 

이 폐쇄 것 실제 사용 사례에서 아마도

test-0 
test-1 
test-2 
test-3 
test-4 

을 인쇄 :

은 당신이하고 싶은 것은, 실행시 변수를 바인딩 할 익명 서브 루틴을 만드는 것입니다 나중에 액세스 할 수 있도록 배열이나 해시에로드 할 수 있습니다.

당신은 여전히 ​​폐쇄와 식별자를 bareword는 사용할 수 있지만 이름이 컴파일시에 볼 수 있습니다 확인하기 위해 약간의 추가 작업을 수행해야합니다

BEGIN { 
    for my $color (qw(red blue green)) { 
     no strict 'refs'; 
     *$color = sub {"<font color='$color'>@_</font>"} 
    } 
} 

print "Throw the ", red 'ball'; # "Throw the <font color='red'>ball</font>" 
7

에릭 스트롬의 대답은 정확한지, 아마 무엇을 보고 싶었지만 바인딩의 세부 사항에 들어 가지 않습니다.

어휘 수명에 대한 간단한 참고 사항 : lexicals이 컴파일시에 생성이 예와 같이, 그 범위를 입력하기도 전에 실제로 가능하다 :

my $i; 
BEGIN { $i = 42 } 
print $i; 

을 그 후에, 그들은 범위 밖으로 갈 때, 그들은 그들이 범위에있는 다음 시간까지 사용할 수 없게됩니다 : 당신의 코드에서

print i(); 
{ 
    my $i; 
    BEGIN { $i = 42 } 
    # in the scope of `my $i`, but doesn't actually 
    # refer to $i, so not a closure over it: 
    sub i { eval '$i' } 
} 
print i(); 

을 폐쇄는 컴파일시에 초기 어휘 $i에 바인딩됩니다. 그러나 foreach 루프는 약간 이상합니다. my $i은 실제로 어휘를 생성하지만 foreach 루프는이를 사용하지 않습니다. 대신 반복되는 각 값의 반복 값 중 하나에 별칭을 지정하고 루프 이후 원래 상태로 복원합니다. 따라서 클로저가 원래 어휘 $i을 참조하는 유일한 것입니다.

약간의 변동이 더 복잡 나타낸다 : 여기

foreach (@foo) { 
    my $i = $_; 
    sub printer { 
     my $blah = shift @_; 
     print "$blah-$i\n"; 
    } 

    printer("test"); 
} 

원래 $i 컴파일시에 작성되어 상기 클로저는 결합; 루프의 첫 번째 반복이 루프를 설정하지만 루프의 두 번째 반복은 클로저와 연결되지 않은 새 $i을 만듭니다.

+0

매우 흥미 롭습니다. 감사합니다. – Snark