5 ответов:
Perl предоставляет
ref()функция, позволяющая проверить тип ссылки перед разыменованием ссылки...С помощью
ref()функция вы можете защитить программный код, который разыменовывает переменные от возникновения ошибок при использовании неправильного типа ссылки...
$xвсегда скаляр. Намек-это сигил$: любая переменная (или разыменование какого-либо другого типа), начиная с$- скаляр. (См.perldoc perldata для получения дополнительной информации о типах данных.)ссылка-это просто определенный тип скаляра. Встроенная функция
refрасскажу вам, что это за Ссылка. С другой стороны, если у вас есть благословенная ссылка,refтолько скажет вам имя пакета ссылка была благословлена, а не фактический тип ядра данных (благословенные ссылки могут быть hashrefs, arrayrefs или другими вещами). Вы можете использовать Скалярные::Util В ' sreftypeрасскажу вам, какой это тип ссылки: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