2014-12-01 2 views
2

객체를 인스턴스화하지 않고 클래스에서 프로토 타입 함수를 호출하려고합니다. 내 수업 MyClass의 예 :클래스의 Perl 프로토 타입 서브 루틴

package MyClass; 
use strict; 
use warnings; 

sub import{ 
     my $class = shift; 
     my ($caller) = caller(); 
     eval "sub ${caller}::myprot(\&);"; 
     eval "*${caller}::myprot = \&MyClass::myprot;";   
} 

sub myprot (&) { 
    my ($f) = @_; 
     $f->(); 
} 

1; 

나는 스크립트 main.pl에서 프로토 타입을 호출 할 :

use strict; 
use warnings; 

use MyClass; 

myprot { 
     print "myprot\n"; 
}; 

와 나는 오류가 점점 오전 :

Use of uninitialized value in subroutine entry at MyClass.pm line 14. 
Use of uninitialized value in subroutine entry at MyClass.pm line 14. 
Undefined subroutine &main::myprot called at main.pm line 8. 

그렇게하지를 정의되지 않은 서브 루틴 오류를 실제로 이해합니다. use을 사용하면 main.pl의 프로토 타입을 정의하는 import이 호출됩니다. 나는 또한 실제로 초기화되지 않은 값 오류를 이해하지 못한다. 나는 약간 설명을 위해 행복 할 것이다.

+0

'myprot (sub {print "myprot \ n"});이 필요하다고 생각합니다. myprot을 MyClass 패키지에서 내 보내야합니다. http://stackoverflow.com/questions/17912400/export-vs-export-ok-in-perl – KeepCalmAndCarryOn

+0

@KeepCalmAndCarryOn : 유효하지 않은 Perl - 아마도 괄호'(..)'대신에 중괄호'{..}'를 사용하려는 것 같습니다. 아니요 - 그는 'MyClass'가 유일한 매개 변수로 코드 블록을 사용하는'myprot' 함수를 선언하기를 원합니다. 그러나 나는 그가'sub'가없는 서브 루틴 정의처럼 보이게해서는 안된다는 것에 동의합니다. – Borodin

+0

나는 실제 코드에서 이것을 * 실제로 사용하려고하지 않는다고 믿는다. 내 대답은 왜 그것이 당신을 위해 일하지 않는지 설명하지만, 당신은 *이 바깥의 실험과 같은 것을해서는 안됩니다. – Borodin

답변

1

정말로 하시겠습니까?

문제는 큰 따옴표가 glob 할당에있는 백 슬래시를 먹게된다는 것입니다.

eval "*${caller}::myprot = \&MyClass::myprot;" 

eval "*${caller}::myprot = \\&MyClass::myprot;" 

해야하지만 당신의 코드를 디버깅달라고하지 마십시오!

5

해당 코드에는 여러 가지 스케치가 있습니다.

확인되지 않은 eval 사용은 실패하면 결코 알 수 없음을 의미합니다. eval은 eval "code" or die [email protected]으로 사용해야합니다. 엄격하면 심볼 테이블을 엉망으로 만들 때 오류 메시지가 나타나기 때문에 오류가 발생합니다 (즉, *name = \&code).

eval을 내보내기 서브 루틴을 사용하면 잔인합니다. eval STRING은 잠재적 인 보안 구멍이므로 최후의 수단으로 사용해야합니다 (eval BLOCK은 괜찮습니다). 평가판을 사용하지 않고 기호 테이블을 조작 할 수 있지만 엄격하게 기호 참조를 사용하는 것은 바람직하지 않습니다.

my $caller = "foo"; 
*{"${caller}::myprot"} = \&MyClass::myprot; 
# Can't use string ("foo::myprot") as a symbol ref while "strict refs" in use... 

먼저 엄격한 설정을 해제해야합니다. 이것은 일반적으로 "앨리어싱"이라고합니다.

no strict 'refs'; 
*{$caller.'::myprot'} = \&myprot; 

프로토 타입을 미리 설정하지 않아도 별칭이 처리합니다.

이것은 모두 불필요한 것으로 밝혀졌으며,이를 위해 여러 가지 모듈이 있습니다. 가장 일반적인 것은 Exporter이며 Perl과 함께 제공됩니다. 이로 인해 사용자 지정 import이 필요하지 않습니다.

use Exporter 'import'; 
our @EXPORT = qw(myprot); 

다른 일반적인 팁 ...

클래스에서 클래스의 이름을 코딩 하드

(즉. \&MyClass::myprot 그냥 \&myprot해야한다)을 피해야한다. 클래스를 변경하거나 코드를 옮기는 것이 더 어려워집니다.

클래스와 내보내기 기능을 모두 갖춘 하이브리드 모듈은 사용하지 않는 것이 좋습니다. 그들은 사용하기 어렵고, 테스트하고, 문서화하고, 이상한 부작용을 일으킨다. myprot을 자체 모듈에 넣어야합니다.

+0

그것은 아주 잘 정리되었습니다. 그러나 나는 OP가 Perl의 비밀스러운 모퉁이에서 놀고 있었고 실제 코드로 사용하지 않을 것으로 생각한다. – Borodin

+0

@ Borodin 나는 그 반대의 것을 꽤 확신합니다. 다행히도, 그들은 지금 두 가지 대답을 가지고 있습니다. :) – Schwern

+0

정말요? 그는 단지 알 수 있습니다. 나는 물을 것이다. – Borodin

8

당신은 수출업자를 찾고 있습니다.

package MyClass; 
use strict; 
use warnings; 

use Exporter qw(import); 

our @EXPORT = qw(myprot); 

sub myprot(&) { 
    my ($f) = @_; 
    $f->(); 
} 

1; 

나는 보통 @EXPORT_OK (use MyClass qw(myprot);의 사용을 필요로하는)보다는 기본적으로 수출을 사용합니다.

+0

잘 작동합니다. 감사합니다! 그러나 나는 아직도'수출자'가하는 일을 정확히 이해하지 못한다. 예를 들어'use '를 사용하지 않고'require MyClass;와'MyClass-> import();'를 실행하면'import'가 실행되지만'myprot'을 호출 할 수 없습니다 – user1981275

+1

'myprot' (그리고 프로토 타입)이 선언되기 전에'myprot'에 대한 호출을 컴파일하십시오.'Use MyClass; '는 기본적으로'BEGIN {require MyClass; MyClass-> import(); }', 그래서 import를 런타임으로 옮겼다. – ikegami

+1

@ user1981275 간단히 말해서 Exporter는 모듈에서 원하는 대부분을 수행하는 가져 오기 루틴을 제공합니다. 'use'와'import'가 어떻게 상호 작용하는지 이해하지 못한다면, 직접 import 루틴을 작성하지 마십시오. [import] (http://perldoc.perl.org/functions/import.html), [use] (http://perldoc.perl.org/functions/use.html) 및 [use use works in 모듈] (http://perldoc.perl.org/perlmod.html#Perl-Modules)을 이해하는 데 도움이 될 수 있습니다. [Prototype] (http://perldoc.perl.org/perlsub.html#Prototypes)도주의해야 할 부분이므로 확실한 이해없이 사용해야합니다. – Schwern