Как узнать, какой тип значения находится в переменной Perl?



Как я могу сказать, какой тип значения переменной на Perl?



$x может быть скаляром, ссылка на массив или ссылка на хэш (или, возможно, другие вещи).

837   5  

5 ответов:

ref ():

Perl предоставляет ref() функция, позволяющая проверить тип ссылки перед разыменованием ссылки...

С помощью ref() функция вы можете защитить программный код, который разыменовывает переменные от возникновения ошибок при использовании неправильного типа ссылки...

$x всегда скаляр. Намек-это сигил $: любая переменная (или разыменование какого-либо другого типа), начиная с $ - скаляр. (См.perldoc perldata для получения дополнительной информации о типах данных.)

ссылка-это просто определенный тип скаляра. Встроенная функция ref расскажу вам, что это за Ссылка. С другой стороны, если у вас есть благословенная ссылка, ref только скажет вам имя пакета ссылка была благословлена, а не фактический тип ядра данных (благословенные ссылки могут быть hashrefs, arrayrefs или другими вещами). Вы можете использовать Скалярные::Util В ' s 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 и т. д.) см. Этот вопрос:как я могу получить функцию ref () Perl для возврата REF, IO и Именующее? и 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") { ...). Также смотрите полиморфизм.

скаляр всегда содержит один элемент. Все, что находится в скалярной переменной, всегда скалярно. Ссылка-это скалярное значение.

если вы хотите знать, если это ссылка, вы можете использовать ref. Если вы хотите знать тип ссылки, вы можете использовать reftype режим от Скаляр:: Util.

если вы хотите знать, если это объект, вы можете использовать blessed режим от Скаляр:: Util. Вас не должно волновать но что такое благословенный пакет? UNIVERSAL есть некоторые методы, чтобы рассказать вам об объекте: если вы хотите проверить, что он имеет метод, который вы хотите позвонить, используйте can; если вы хотите, чтобы увидеть, что он наследует от чего-то, используйте isa; и если вы хотите видеть, что объект обрабатывает роль, используйте DOES.

если вы хотите знать, если этот скаляр на самом деле просто действует как скаляр, но привязан к классу, попробуйте tied. Если вы получаете объект, продолжайте проверяет.

если вы хотите знать, если это выглядит как количество, вы можете использовать looks_like_number С Скаляр:: Util. Если это не похоже на число, и это не Ссылка, это строка. Однако, все простые значения могут быть строками.

Если вам нужно сделать что-то более причудливое, вы можете использовать такой модуль, как 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 };

затем сделайте Foo поддерживает это (в этом определении класса):

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 an even number less than 42 вместо arg is something else.

ремонтопригодны.

в какой-то момент я прочитал достаточно убедительный аргумент на Perlmonks, который проверяет тип скаляра с ref или reftype - это плохая идея. Я не помню, кто выдвинул эту идею или ссылку. Извиняюсь.

дело в том, что в Perl есть много механизмов, которые позволяют сделать данный скалярный акт похожим на все, что вы хотите. Если вы tie файловый хэндл, так что он действует как хэш, тестирование с reftype скажет вам, что у вас есть filehanle. Оно не скажу вам, что вы должны использовать его как хэш.

Итак, аргумент пошел, лучше использовать duck typing, чтобы узнать, что такое переменная.

вместо:

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

вы должны сделать что-то вроде этого:

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

по большей части я на самом деле не делать этого, но в некоторых случаях у меня. Я все еще решаю, когда этот подход подходит. Я решил выбросить эту концепцию для дальнейшего обсуждения. Я бы с удовольствием посмотрела комментарии.

обновление

я понял, что должен высказать свои мысли по этому поводу.

этот метод имеет преимущество обработки все, что вы бросаете на него.

он имеет недостаток быть громоздким, и несколько странно. Наткнувшись на это в каком-то коде, я бы выпустил большой жирный "WTF".

мне нравится идея проверить, является ли скаляр действует как a hash-ref, вернее что ли это хэш-Реф.

мне не нравится эта реализация.

Comments

    Ничего не найдено.