如何判断Perl变量中的值类型?

pm1*_*100 57 perl

如何判断Perl变量中的值类型?

$x 可能是标量,对数组的引用或对哈希(或其他东西)的引用.

ctd*_*ctd 53

ref():

Perl提供了这个ref()函数,以便您可以在取消引用引用之前检查引用类型...

通过使用该ref()函数,您可以保护程序代码,当使用错误的引用类型时,该代码可以解除引用变量的错误...

  • @Chris:是的,所以如果变量不是引用,你可以推断它是一个简单的标量,因为它什么都不返回.否则,你会知道它是什么样的参考. (8认同)
  • 我认为pm100是关于SO的15个char评论约束. (6认同)
  • 我以为ref()只会告诉你它是什么类型的引用,如果它不是一个则返回什么. (3认同)

Eth*_*her 43

$x永远是一个标量.提示是sigil $:任何变量(或其他类型的解引用)$都是标量.(有关数据类型的更多信息,请参阅perldoc perldata.)

引用只是一种特殊类型的标量.内置函数ref将告诉您它是什么类型的引用.另一方面,如果你有一个受祝福的引用,ref只会告诉你引用的包名称,而不是数据的实际核心类型(祝福引用可以是hashrefs,arrayrefs或其他东西).您可以使用标量::的Utilreftype会告诉你它是什么类型的参考:

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";
Run Code Online (Sandbox Code Playgroud)

...产生输出:

type of x: My::Foo
type of y: HASH
base type of x: HASH
base type of y: HASH
Run Code Online (Sandbox Code Playgroud)

有关其他类型引用的更多信息(例如coderef,arrayref等),请参阅此问题:如何让Perl的ref()函数返回REF,IO和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") { ...).另见多态性.

  • 请注意,根据定义,reftype违反了封装,因此除非您有充分的理由,否则应该避免使用. (3认同)
  • 如果你确实使用reftype,请注意它为非引用返回undef,因此像`reftype($ x)eq'HASH'这样的代码可能会导致警告.(参考,另一方面,对于非参考,方便地返回''.) (2认同)

bri*_*foy 18

标量始终包含单个元素.标量变量中的任何内容始终是标量.引用是标量值.

如果您想知道它是否是参考,您可以使用ref.如果您想知道引用类型,可以使用Scalar :: Util中reftype例程.

如果您想知道它是否是对象,可以使用Scalar :: Util中blessed例程.不过,你永远不应该关心受祝福的包裹是什么.有一些方法可以告诉你一个对象:如果你想检查它是否有你要调用的方法,请使用; 如果你想看到它继承自某些东西,请使用; 如果你想看到对象处理一个角色,请使用.UNIVERSALcanisaDOES

如果你想知道这个标量是否实际上只是一个标量,但是与一个类相关联,那就试试吧tied.如果您有对象,请继续检查.

如果你想知道,如果它看起来像一个号码,你可以使用looks_like_number标量::的Util.如果它看起来不像数字并且它不是引用,那么它就是一个字符串.但是,所有简单值都可以是字符串.

如果您需要做一些更奇特的事情,可以使用Params :: Validate等模块.


jro*_*way 6

我喜欢多态而不是手动检查某些东西:

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
Run Code Online (Sandbox Code Playgroud)

这比手动检查强大得多,因为您可以像使用任何其他类型约束一样重用“检查”。这意味着当您想要处理数组、散列和小于 42 的偶数时,您只需为“小于 42 的偶数”编写一个约束,并为这种情况添加一个新的多方法。“调用代码”不受影响。

您的类型库:

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

subtype EvenNumberLessThan42, as Num, where { $_ < 42 && $_ % 2 == 0 };
Run Code Online (Sandbox Code Playgroud)

然后让 Foo 支持这个(在那个类定义中):

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

    multi method foo (EvenNumberLessThan42 $arg) { say "arg is an even number less than 42" }
}
Run Code Online (Sandbox Code Playgroud)

然后Foo->new->foo(40)打印arg is an even number less than 42而不是arg is something else.

可维护。