[perl] 일부 사용자는 왜 Perl에서 클래스 이름을 인용합니까?

를 보면 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"->newnot을 호출합니다 "Foo"->new. 서브 루틴 해결을 어떻게 중지합니까? 당신은 그것을 인용 할 수 있습니다.

"Foo"->new();

성능의 의미에 관해서는, 간단한 단어보다는 문자열을 사용하여 상황을 악화시키지 않습니다. 에 의해 생성 된 optree O=Deparse가 동일 하다는 것을 확인했습니다 . 따라서 일반적으로 정확성을 평가하면 클래스 이름을 인용하는 것이 좋습니다.

이것은 Programming Perl에 언급되어 있습니다 (슬프게도 간접 메소드 호출 의 맥락에서 )

… 그래서 우리는 거의 항상 두 가지 사실에 해당하는 경우 거의 항상 클래스 이름으로 벗어날 수 있다고 말할 것입니다. 먼저, 클래스와 동일한 이름의 서브 루틴이 없습니다. ( start start 소문자와 같은 서브 루틴 new이름과 ElvenRingstart 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"를로드하지 않았습니까?).


답변