2010-05-17 4 views
4

문서를 다른 형식으로 변환 한 다음 형식 문서를 기반으로 다른 함수를 호출합니다. 그것은 약간의 정리를 필요로하는 HTML 문서를 제외하고는 모든 것이 꽤나 간단합니다. 그리고 그 정리는 그것이 어디서 왔는지에 따라 다릅니다. 그래서 저는 서브 루틴에 대한 참조를 convert 함수에 전달하여 호출자가 HTML을 수정할 수있는 기회를 갖도록 할 수 있다고 생각했습니다. (나는 직장에 있지 않아 복사 및 붙여 넣기가되지 않습니다.) : 다음에 의해 호출되는서브 루틴 참조에 전달 된 스칼라 참조를 어떻게 수정할 수 있습니까?

package Converter; 
... 
sub convert 
{ 
    my ($self, $filename, $coderef) = @_; 

    if ($filename =~ /html?$/i) { 
     $self->_convert_html($filename, $coderef); 
    } 
} 

sub _convert_html 
{ 
    my ($self, $filename, $coderef) = @_; 

    my $html = $self->slurp($filename); 
    $coderef->(\$html); #this modifies the html 
    $self->save_to_file($filename, $html); 
} 

:

Converter->new->convert("./whatever.html", sub { s/<html>/<xml>/i }); 

내가이 라인을 따라 다른 몇 가지를 시도했지만 나는 (대체에 '초기화되지 않은 값의 사용을 받고 계속의 ///) '. 내가하려는 일을하는 어떤 방법이 있을까요?

+1

아래의 답을 읽기 전에 : 각 서브 루틴 수준에서 몇 가지 인쇄 문을 추가하여 인수로 얻는 것이 실제로 생각하는 것과 일치하는지 확인하십시오 가야 해. ** 힌트 : 대체 코드 레터 안의 print 문은 답을 찾으실 것입니다 ** ** – Ether

답변

5

, 나는 스칼라 심판을 수정 피할 것이다 단지 변경된 값 반환 :. 당신이 원하는 경우에, 그러나

sub _convert_html 
{ 
    my ($self, $filename, $coderef) = @_; 

    my $html = $self->slurp($filename); 
    $html = $coderef->($html); #this modifies the html 
    $self->save_to_file($filename, $html); 
} 

을 sub의 인수를 수정하려면 Perl에서 모든 하위 인수가 참조로 전달된다는 것을 알아야합니다 (@_의 요소는 부속 호출의 인수로 별칭이 지정됩니다).그래서 전환 서브처럼 보일 수 있습니다

sub { $_[0] =~ s/<html>/<xml>/ } 

하지만 당신이 정말로, $_에서 작동 할 경우에 당신이 원하는 코드 예제에 가지고있는 것처럼, 당신은 _convert_html() 모양처럼 만들 필요가 :

sub _convert_html 
{ 
    my ($self, $filename, $coderef) = @_; 

    my $html = $self->slurp($filename); 

    $coderef->() for $html; 

    $self->save_to_file($filename, $html); 
} 

for$_을 올바르게 현지화하는 쉬운 방법입니다. 당신은 또한 할 수 있습니다 :

sub _convert_html 
{ 
    my ($self, $filename, $coderef) = @_; 

    local $_ = $self->slurp($filename); 

    $coderef->(); 

    $self->save_to_file($filename, $_); 
} 
+0

자세한 설명 주셔서 감사합니다 :-) – Mark

+2

복사가 많이 있습니다. 먼저 인수 스택에 넣은 다음 변경하고 인수 스택에 다시 복사합니다. 많은 페이지를 처리해야하는 경우 해를 끼칠 수 있습니다. –

+1

속도가 중요하다면'local'은 하나의 항목으로'for'보다 빠릅니다. –

2

이 시도

감사 :

Converter->new->convert("./whatever.html", sub { ${$_[0]} =~ s/<html>/<xml>/i; }); 

대체가 ($_이 범위에 정의되어 있지 않습니다)에서 작동하도록 아무것도 제공하지 않기 때문에 당신은 초기화되지 않은 값 경고를 받고있다. 그 값을 어디서 찾을 지 알려줄 필요가 있습니다 (참조로 @_).

당신이 공상 싶은 경우에 당신은 기본적으로 모든 인수에서 작동 코드 참조 할 수 있습니다 :

sub { map { $$_ =~ s/<html>/<xml>/i } @_ } 
+0

지도 코드 예제에서 반환 값을 원하는 것이 무엇인지 궁금합니다. :) –

+0

@ 브라이언 : 참으로; 일반적으로 참조를 사용하는 대신 새 값 (들)을 반환하는 변환 하위를 작성합니다. – Ether

3

자체에 의한 s///$_에서 작동하지만 스칼라 참조가 콜백으로 전달되는 것을 기억하십시오 sub를 인수로 취하므로 @_ 배열에 있습니다.

sub { my ($ref) = @_; $$ref =~ s/<html>/<xml>/i } 

를 또는, 펄 서브 루틴 인수의 별칭 특성을 활용할 수 있고, 직접 수정 :

그래서 당신은 이런 식으로 콜백 서브를 변경할 수 있습니다

sub _convert_html { 
    ... 
    $coderef->($html); 
} 

그리고 나서

sub { $_[0] =~ s/<html>/<xml>/i } 

(이것은 실제로 원래의 문자열을 l 인수로 옹은 스칼라 변수가 아니라 리터럴 문자열입니다) 그것은 나를라면

관련 문제