IT story

Perl 변수에 어떤 유형의 값이 있는지 어떻게 알 수 있습니까?

hot-time 2020. 12. 29. 07:54
반응형

Perl 변수에 어떤 유형의 값이 있는지 어떻게 알 수 있습니까?


Perl 변수에 어떤 유형의 값이 있는지 어떻게 알 수 있습니까?

$x 스칼라, 배열에 대한 참조 또는 해시에 대한 참조 (또는 다른 것) 일 수 있습니다.


ref () :

Perl은 ref()참조를 역 참조하기 전에 참조 유형을 확인할 수 있도록 함수를 제공합니다 .

ref()함수를 사용하면 잘못된 참조 유형을 사용할 때 변수를 역 참조하는 프로그램 코드가 오류를 생성하지 않도록 보호 할 수 있습니다.


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

참조는 특정 유형의 스칼라입니다. 내장 함수 ref는 그것이 어떤 종류의 참조인지 알려줍니다. 반면에 축복받은 참조가있는 경우 ref데이터의 실제 핵심 유형이 아닌 참조가 축복받은 패키지 이름 만 알려줍니다 (축복 참조는 해시 참조, 배열 참조 또는 기타 항목 일 수 있음). 당신이 사용할 수있는 스칼라 :: 백분율 의는 reftype그것이 참조 어떤 종류의 당신을 말할 것이다 :

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";

... 출력을 생성합니다.

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

다른 유형의 참조 (예 : coderef, arrayref 등)에 대한 자세한 내용은 다음 질문을 참조하십시오. Perl의 ref () 함수를 사용하여 REF, IO 및 LVALUE를 반환하려면 어떻게해야합니까? perldoc perlref .

참고 : 축복 된 객체 (예 :)로 코드 분기를 구현 하는 데를 사용 해서는 안됩니다 . 변수 유형에 따라 결정을 내려야하는 경우 (예 : 또는 )를 사용하십시오. 다형성을 참조하십시오 .ref$ref($a) eq "My::Foo" ? say "is a Foo object" : say "foo not defined";isaif ($a->isa("My::Foo") { ...if ($a->can("foo") { ...


스칼라는 항상 단일 요소를 보유합니다. 스칼라 변수에있는 것은 항상 스칼라입니다. 참조는 스칼라 값입니다.

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

객체인지 알고 싶다면 Scalar :: Utilblessed루틴을 사용할 수 있습니다 . 하지만 축복받은 패키지가 무엇인지 신경 쓰지 말아야합니다. 객체에 대해 알려주는 몇 가지 메소드가 있습니다 . 호출하려는 메소드가 있는지 확인하려면 ; 무언가에서 상속되는지 확인하려면 ; 객체가 역할을 처리하는 것을 보려면을 사용하십시오 .UNIVERSALcanisaDOES

해당 스칼라가 실제로 스칼라처럼 작동하지만 클래스에 연결되어 있는지 알고 싶다면 tied. 물건을 받으면 계속 확인하십시오.

숫자처럼 보이는지 알고 싶다면 Scalar :: Utillooks_like_number 에서 사용할 수 있습니다 . 숫자처럼 보이지 않고 참조가 아니라면 문자열입니다. 그러나 모든 단순 값은 문자열이 될 수 있습니다.

좀 더 멋진 일을해야한다면 Params :: Validate 와 같은 모듈을 사용할 수 있습니다 .


수동으로 무언가를 확인하는 대신 다형성을 좋아합니다.

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 };

Then make Foo support this (in that class definition):

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

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

Then Foo->new->foo(40) prints arg is an even number less than 42 instead of arg is something else.

Maintainable.


At some point I read a reasonably convincing argument on Perlmonks that testing the type of a scalar with ref or reftype is a bad idea. I don't recall who put the idea forward, or the link. Sorry.

The point was that in Perl there are many mechanisms that make it possible to make a given scalar act like just about anything you want. If you tie a filehandle so that it acts like a hash, the testing with reftype will tell you that you have a filehanle. It won't tell you that you need to use it like a hash.

So, the argument went, it is better to use duck typing to find out what a variable is.

Instead of:

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;
}

You should do something like this:

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;
}

For the most part I don't actually do this, but in some cases I have. I'm still making my mind up as to when this approach is appropriate. I thought I'd throw the concept out for further discussion. I'd love to see comments.

Update

I realized I should put forward my thoughts on this approach.

This method has the advantage of handling anything you throw at it.

It has the disadvantage of being cumbersome, and somewhat strange. Stumbling upon this in some code would make me issue a big fat 'WTF'.

I like the idea of testing whether a scalar acts like a hash-ref, rather that whether it is a hash ref.

I don't like this implementation.

ReferenceURL : https://stackoverflow.com/questions/1731333/how-do-i-tell-what-type-of-value-is-in-a-perl-variable

반응형