를 보면 Type::Tiny
호출 할 때 클래스 이름 Type::Tiny->new
이 공식 문서에 인용되어 있음을 알 수 있습니다.
my $NUM = "Type::Tiny"->new(
name => "Number",
constraint => sub { looks_like_number($_) },
message => sub { "$_ ain't a number" },
);
왜 이런거야? 이것은 단순한 스타일입니까? 이 연습에 성능상의 영향이 있습니까?
답변
더 간단한 예를 들어
package Foo { sub new { die 7 } };
package Bar { sub new { die 42 } };
sub Foo { "Bar" }
Foo->new();
위의 예에서 상수 Foo
는 “Bar”로 해석되므로 "Bar"->new
not을 호출합니다 "Foo"->new
. 서브 루틴 해결을 어떻게 중지합니까? 당신은 그것을 인용 할 수 있습니다.
"Foo"->new();
성능의 의미에 관해서는, 간단한 단어보다는 문자열을 사용하여 상황을 악화시키지 않습니다. 에 의해 생성 된 optree O=Deparse
가 동일 하다는 것을 확인했습니다 . 따라서 일반적으로 정확성을 평가하면 클래스 이름을 인용하는 것이 좋습니다.
이것은 Programming Perl에 언급되어 있습니다 (슬프게도 간접 메소드 호출 의 맥락에서 )
… 그래서 우리는 거의 항상 두 가지 사실에 해당하는 경우 거의 항상 클래스 이름으로 벗어날 수 있다고 말할 것입니다. 먼저, 클래스와 동일한 이름의 서브 루틴이 없습니다. ( start start 소문자와 같은 서브 루틴
new
이름과ElvenRing
start uppercase 와 같은 클래스 이름 이라는 규칙을 따르면 문제가되지 않습니다.) 둘째, 클래스에 다음 중 하나가로드되었습니다use ElvenRing; require ElvenRing;
이러한 선언 중 하나를 사용하면 Perl이
ElvenRing
모듈 이름 을 알 수 있습니다 . 이는 현재 패키지에서 자신 의 서브 루틴을 선언 한 경우에도new
클래스 이름 이전 과 같은 기본 이름ElvenRing
이 메소드 호출로 해석되도록new
합니다.
그리고 그것은 의미가 있습니다 : 여기서 혼동은 서브 루틴 (일반적으로 소문자)이 클래스와 같은 이름 (일반적으로 대문자) 인 경우에만 발생할 수 있습니다. 위의 명명 규칙을 위반하는 경우에만 발생할 수 있습니다.
tldr; 클래스 이름을 알고 클러 터보다 정확성을 중요하게 생각한다면 클래스 이름을 인용하는 것이 좋습니다.
참고 사항 : 또는 ::
예를 들어 위와 같이 끝에 a 를 붙여서 함수에 대한 베어 워드의 해상도를 중지 할 수 있습니다 Foo::->new
.
의견을 보내 주신 reddit의 Ginnz 와 의견 을 주신 Toby Inkster 에게 감사 의 말을 전합니다 (처음 읽었을 때 나에게 의미가 없었 음).
답변
문자열로 취급되는 베어 워드를 사용하지 않고 클래스 이름을 명시 적으로 인용하는 것은 구문 상 모호성을 피하는 세 가지 방법 중 하나입니다. perlobj 문서 의 호출 클래스 메소드 섹션에 설명되어 있습니다.
Perl에서는 패키지 이름 및 서브 루틴 이름에 베어 워드를 사용할 수 있으므로 베어 워드의 의미를 잘못 해석하는 경우가 있습니다. 예를 들어, 구문
Class->new()
은'Class'->new()
또는 으로 해석 될 수 있습니다Class()->new()
. 영어에서 두 번째 해석은 “라는 서브 루틴Class()
을 호출 한 다음new()
반환 값에 대한 메소드 로 호출 “로 읽습니다Class()
.Class()
현재 네임 스페이스에 이름이 지정된 서브 루틴이있는 경우 Perl은 항상Class->new()
두 번째 대안, 즉에 대한 호출에new()
의해 리턴 된 오브젝트에 대한 호출로
해석 합니다Class()
.
아래의 데모와 함께이 이상한 경우를보십시오.
#! /usr/bin/env perl
use strict;
use warnings;
sub Type::Tiny { print "Returning Bogus\n" ; return "Bogus" }
sub Type::Tiny::new { print "Type::Tiny::new\n" }
sub Bogus::new { print "Bogus::new\n" }
my $class = "Type::Tiny";
Type::Tiny->new;
Type::Tiny::->new;
"Type::Tiny"->new;
$class->new;
출력은
돌아 오는 가짜 가짜 :: 새로운 유형 :: 작은 :: 새로운 유형 :: 작은 :: 새로운 유형 :: 작은 :: 새로운
앞에서 언급 한 나머지 문서 섹션에서는 놀라운 동작이나 실수로 인한 오류를 방지하는 방법을 보여줍니다.
Perl이 두 가지 방식으로 첫 번째 해석 ( 즉 ,라는 클래스의 메소드 호출) 을 사용하도록 할 수 있습니다
"Class"
. 먼저::
클래스 이름에 a 를 추가 할 수 있습니다 .Class::->new()
Perl은이를 항상 메소드 호출로 해석합니다.
또는 클래스 이름을 인용 할 수 있습니다.
'Class'->new()
물론 클래스 이름이 스칼라 인 경우 Perl도 올바른 작업을 수행합니다.
my $class = 'Class'; $class->new();
귀하의 질문에 적용하면 아래의 모든 통화는 동일합니다.
Type::Tiny::->new( … );
"Type::Tiny"->new( … );
my $class = "Type::Tiny";
$class->new( … );
::
끝에 추가 하면 유용한 경고가 생성되는 이점이 있습니다. 실수로 입력했다고
Type::Tinny::->new;
그 생산
Bareword "Type :: Tinny ::"는 ./try 15 행에 존재하지 않는 패키지를 나타냅니다. ./try 15 행에서 "Type :: Tinny"패키지를 통해 "new"객체 메소드를 찾을 수 없습니다 ( "Type :: Tinny"를로드하지 않았습니까?).