2009-11-13 9 views

답변

44

ref() : 당신이 참조를 역 참조하기 전에 참조 유형을 확인할 수 있도록

펄이 ref() 기능을 제공합니다 ...

당신의 변수를 역 참조 프로그램 코드를 보호 할 수 있습니다 ref() 기능을 사용하여 잘못된 유형의 참조가 사용될 때 오류가 발생합니다 ...

+1

ref()는 참조 유형이 무엇인지 알려주고 하나가 아닌 경우 아무것도 반환하지 않는다고 생각했습니다. –

+3

thx - 음 나는 thx 만 말하고 싶었지만 - 허용되지 않았다. – pm100

+7

@Chris : 맞아요. 변수가 참조가 아니라면 아무것도 반환하지 않는다는 단순한 스칼라라고 추론 할 수 있습니다. 그렇지 않으면 어떤 종류의 참조인지 알 수 있습니다. –

40

$x은 항상 스칼라입니다. 힌트는 $입니다. $으로 시작하는 모든 변수 (또는 다른 유형의 참조 해제)는 스칼라입니다. (데이터 형식에 대한 자세한 내용은 perldoc perldata을 참조하십시오.)

참조는 스칼라의 특정 유형입니다. 내장 함수 ref은 어떤 종류의 참조인지 알려줍니다. 반면 축복받은 참조가있는 경우 ref은 데이터의 실제 핵심 유형이 아닌 참조가 축복 된 패키지 이름 만 알려줍니다 (축복 참조는 hashrefs, arrayrefs 또는 기타 일 수 있음).

use Scalar::Util qw(reftype); 

my $x = bless {}, 'My::Foo'; 
my $y = { }; 

print "type of x: " . ref($x) . "\n"; 
print "type of y: " . ref($y) . "\n"; 
print "base type of x: " . reftype($x) . "\n"; 
print "base type of y: " . reftype($y) . "\n"; 

은 ... 출력을 생성합니다 : 당신은이 기준의 어떤 종류의 당신을 말할 것이다 Scalar::Utilreftype를 사용할 수있다 (참고 문헌의 다른 유형에 대한 자세한 내용은

type of x: My::Foo 
type of y: HASH 
base type of x: HASH 
base type of y: HASH 

를 예를 들어 코드 참조 , arrayref 등)에 대한 자세한 내용은 How can I get Perl's ref() function to return REF, IO, and LVALUE?perldoc perlref을 참조하십시오.

참고 : 당신은 하지 사용 ref는 축복 객체 코드 가지를 구현하는해야한다 (예를 들면 $ref($a) eq "My::Foo" ? say "is a Foo object" : say "foo not defined";) - 당신은 변수의 유형에 따라 어떤 결정을 사용해야 할 경우 isa (즉 if ($a->isa("My::Foo") { ... 또는 if ($a->can("foo") { ...) . 또한 polymorphism을 참조하십시오.

+3

reftype은 캡슐화에 위배되므로 정의에 따르면 아주 좋은 이유가없는 한 피해야합니다. – ysth

+2

reftype을 사용한다면, 'reftype ($ x) eq'HASH '와 같은 코드가 경고를 초래할 수 있으므로 참조가 아닌 경우 undef를 반환한다는 점에 유의하십시오. (ref, 반면에, 편리하게 non-references를 위해 ''를 반환합니다.) – ysth

+0

@ysth : 꽤 그렇습니다! 내 답변을 업데이트했습니다. 축복받은 객체에 대한'ref'를 잘 사용하는 것은 드뭅니다. – Ether

14

스칼라에는 항상 단일 요소가 들어 있습니다. 스칼라 변수에있는 것은 항상 스칼라입니다. 참조는 스칼라 값입니다.

참조 용인지 알고 싶다면 ref을 사용할 수 있습니다. 참조 유형을 알고 싶으면 Scalar::Utilreftype 루틴을 사용할 수 있습니다.

개체인지 여부를 알고 싶다면 blessed 루틴을 Scalar::Util에서 사용할 수 있습니다. 그래도 축복받은 패키지가 무엇인지 신경 쓰지 않아야합니다. UNIVERSAL에는 개체에 대해 알려주는 몇 가지 방법이 있습니다. 호출 할 메서드가 있는지 확인하려면 can; 어떤 것을 상속 받고 싶다면 isa; 개체가 역할을 처리하는지 확인하려면 DOES을 사용하십시오.

스칼라가 실제로 스칼라처럼 작동하지만 클래스에 묶여 있는지 알고 싶으면 tied을 시도하십시오.물건을 얻으면 수표를 계속하십시오.

숫자로 보이는지 알고 싶다면 looks_like_numberScalar::Util에서 사용할 수 있습니다. 숫자처럼 보이지 않고 참조가 아닌 경우 문자열입니다. 그러나 모든 단순 값은 문자열 일 수 있습니다.

좀 더 멋진 작업이 필요한 경우 Params::Validate과 같은 모듈을 사용할 수 있습니다.

2

필자는 Perlmonks에서 스칼라의 유형을 ref 또는 reftype으로 테스트하는 것이 합당한 설득력있는 주장이라고 읽는 것이 좋습니다. 아이디어를 전달한 사람이나 링크를 누가 기억하지 못합니다. 죄송합니다.

요점은 Perl에서 원하는 스칼라 동작을 가능하게 만드는 많은 메커니즘이 있다는 것입니다. tie 해시처럼 작동하도록 파일 핸들을 사용하면 reftype으로 테스트하면 파일 공유 있음을 알 수 있습니다. 해시처럼 사용해야한다고 말하지는 않습니다.

그래서 변수가 무엇인지 알기 위해 오리 타이핑을 사용하는 것이 좋습니다. 대신

:

sub foo { 
    my $var = shift; 
    my $type = reftype $var; 

    my $result; 

    eval { 
     $result = $var->{foo}; 
     1; # guarantee a true result if code works. 
    } 
    or eval { 
     $result = $var->[3]; 
     1; 
    } 
    or do { 
     $result = 'foo'; 
    } 

    return $result; 
} 
실제로이 작업을 수행하지 않는 대부분의 경우

,하지만이 경우에 :

sub foo { 
    my $var = shift; 
    my $type = reftype $var; 

    my $result; 
    if($type eq 'HASH') { 
     $result = $var->{foo}; 
    } 
    elsif($type eq 'ARRAY') { 
     $result = $var->[3]; 
    } 
    else { 
     $result = 'foo'; 
    } 

    return $result; 
} 

당신이 뭔가를 할 것이다. 이 방법이 적절한시기에 대해서는 여전히 마음을 움직이고 있습니다. 나는 더 많은 논의를 위해 개념을 버릴 것이라고 생각했다. 나는 코멘트를보고 싶다.

나는이 방법 앞으로 내 생각을 넣어해야 실현

업데이트.

이 방법은 던지는 물건을 다룰 때 이점이 있습니다.

이것은 번거롭고 다소 이상하다는 단점이 있습니다. 일부 코드에서이 문제가 발생하면 큰 뚱뚱한 'WTF'가 나옵니다.

나는 스칼라 과 같은 역할을하는지, 아니면 해쉬 ref인지 여부를 테스트하는 것을 좋아합니다.

저는이 구현이 마음에 들지 않습니다.

+4

나는 아마도 당신이 생각하고있는 사람 일 것이다. 나는 리터럴 문자열에 대해서는 테스트하지 않는다. 프로토 타입에 대한 테스트 : if (ref $ f eq ref {}). 넥타이는 tied()로 시작합니다. 객체가 있으면 정상적인 작업을 수행합니다. –

+2

절대로 결코 그런 식의 refs 테스트는 절대로하지 마십시오. 더 쉽게 할 수 있습니다. :) –

+0

두뇌, 그건 또 다른 흥미로운 점입니다. 내가 생각했던 것이 아닙니다. 나는 당신의 요점을 볼 수 있습니다. – daotoad

4

나는 수동으로 뭔가를 확인하는 대신 다형성을 좋아한다 : 당신은 다른 종류의 제약 것처럼 당신이 당신의 "확인"을 다시 사용할 수

use MooseX::Declare; 

class Foo { 
    use MooseX::MultiMethods; 

    multi method foo (ArrayRef $arg){ say "arg is an array" } 
    multi method foo (HashRef $arg) { say "arg is a hash" } 
    multi method foo (Any $arg)  { say "arg is something else" } 
} 

Foo->new->foo([]); # arg is an array 
Foo->new->foo(40); # arg is something else 

이 훨씬 더 강력한 수동 검사보다. 즉, 배열, 해시 및 심지어 42보다 작은 수를 처리하려는 경우 "42보다 작은 수의 짝수"에 대한 제약 조건을 작성하고이 경우에 대해 새로운 다중 방법을 추가하면됩니다. "호출 코드"는 영향을받지 않습니다.

형식 라이브러리 :

package MyApp::Types; 
use MooseX::Types -declare => ['EvenNumberLessThan42']; 
use MooseX::Types::Moose qw(Num); 

subtype EvenNumberLessThan42, as Num, where { $_ < 42 && $_ % 2 == 0 }; 

그런 다음 푸이 (즉, 클래스 정의)을 지원합니다

class Foo { 
    use MyApp::Types qw(EvenNumberLessThan42); 

    multi method foo (EvenNumberLessThan42 $arg) { say "arg is an even number less than 42" } 
} 

그런 Foo->new->foo(40) 인쇄 대신 arg is something elsearg is an even number less than 42.

유지 관리 가능.

관련 문제