【问题标题】:Why shouldn't I use UNIVERSAL::isa?为什么我不应该使用 UNIVERSAL::isa?
【发布时间】:2021-01-07 04:59:56
【问题描述】:

据此

http://perldoc.perl.org/UNIVERSAL.html

我不应该使用 UNIVERSAL::isa() 而应该使用 $obj->isa() 或 CLASS->isa()。

这意味着首先要找出某个东西是否是引用,然后是对这个类的引用,我必须这样做

eval { $poss->isa("Class") }

然后检查 $@ 和所有这些口香糖,否则

use Scalar::Util 'blessed';
blessed $ref && $ref->isa($class);

我的问题是为什么?像这样调用 UNIVERSAL::isa 有什么问题?对于以下内容,它更干净:

my $self = shift if UNIVERSAL::isa($_[0], __PACKAGE__)

查看是否在对象上调用此函数。有没有一个很好的干净替代方案,不会因为 & 符号和潜在的长线而变得繁琐?

【问题讨论】:

    标签: perl


    【解决方案1】:

    主要问题是,如果您直接调用UNIVERSAL::isa,您将绕过任何重载isa 的类。如果这些类依赖于重载行为(他们可能会这样做,否则他们不会覆盖它),那么这是一个问题。如果你直接在你的祝福对象上调用isa,那么在任何一种情况下都会调用正确的isa方法(如果存在则重载,如果不存在则为UNIVERSAL::。

    第二个问题是UNIVERSAL::isa 只会像isa 的所有其他用法一样,对受祝福的引用执行您想要的测试。对于非祝福引用和简单标量,它具有不同的行为。因此,您的示例不检查 $ref 是否被祝福并没有做正确的事情,您忽略了错误条件并使用 UNIVERSAL 的替代行为。在某些情况下,这可能会导致细微的错误(例如,如果您的变量包含类的名称)。

    考虑:

    use CGI;
    
    my $a = CGI->new();
    
    my $b = "CGI";
    
    print UNIVERSAL::isa($a,"CGI");  # prints 1, $a is a CGI object.
    print UNIVERSAL::isa($b,"CGI");  # Also prints 1!! Uh-oh!!
    

    因此,总而言之,不要使用 UNIVERSAL::isa... 进行额外的错误检查并直接在您的对象上调用 isa

    【讨论】:

    • UNIVERSAL::isa 不需要祝福参考。它也适用于 unblessed 引用(例如,UNIVERSAL::isa([7],'ARRAY') 返回 1)。如文档中所述,如果您将字符串传递给它,它会将其视为类名(如您的示例所示)。
    • 当然,有一段时间you actually want that second issue ...但你必须注意其他限制,如果这是你想要做的。
    【解决方案2】:

    请参阅 UNIVERSAL::isaUNIVERSAL::can 的文档,了解为什么不应该这样做。

    简而言之,有些重要的模块确实需要覆盖“isa”(例如Test::MockObject),如果将其作为函数调用,就会破坏它。

    我不得不说,my $self = shift if UNIVERSAL::isa($_[0], __PACKAGE__) 在我看来不是很干净——反 Perl 的拥护者会抱怨线路噪音。 :)

    【讨论】:

    • 感谢您比我更好地解释“为什么不”! +1
    【解决方案3】:

    直接回答你的问题,答案在你链接的页面底部,即如果一个包定义了isa方法,那么直接调用UNIVERSAL::isa不会调用包isa方法。从面向对象的角度来看,这是非常不直观的行为。

    这篇文章的其余部分只是更多关于你为什么要这样做的问题。

    在上述代码中,特定的isa 测试在什么情况下会失败?即,如果它是一个方法,在这种情况下,第一个参数不是包类或其实例吗?

    我问这个是因为我想知道您是否有正当理由首先要测试第一个参数是否是一个对象。即,您是否只是想抓住人们说FooBar::method 而不是FooBar->method$foobar->method?我猜 Perl 不是为这种溺爱而设计的,如果人们错误地使用 FooBar::method,他们很快就会发现。

    您的里程可能会有所不同。

    【讨论】:

      【解决方案4】:

      其他人都告诉过你为什么你不想使用UNIVERSAL::isa,因为当事情过载isa 时它会中断。如果他们已经养成了重载这种非常特殊方法的所有习惯,那么您当然要尊重它。当然,您可以这样写:

      if (eval { $foo->isa("thing") }) {
           # Do thingish things
      }
      

      因为eval 保证在抛出异常时返回 false,否则返回最后一个值。但这看起来糟糕,你不应该以有趣的方式编写代码,因为语言希望你这样做。我们真正想要的只是写:

      if ( $foo->isa("thing") ) {
           # Do thingish things
      }
      

      为此,我们必须确保$foo 始终是一个对象。但是$foo 可以是字符串、数字、引用、未定义的值或各种奇怪的东西。 Perl 不能让 everything 成为一流的对象,真是太可惜了。

      哦,等等,它可以...

      use autobox;   # Everything is now a first class object.
      use CGI;       # Because I know you have it installed.
      
      my $x = 5;
      my $y = CGI->new;
      
      print "\$x is a CGI object\n" if $x->isa('CGI');   # This isn't printed.
      print "\$y is a CGI object\n" if $y->isa('CGI');   # This is!
      

      您可以从 CPAN 获取 autobox。您还可以将它与词法范围一起使用,因此所有内容都可以成为您想要使用->isa() 的文件或块的第一类对象,而不会带来额外的麻烦。它还比我在这个简单示例中介绍的内容多很多

      【讨论】:

      • 我个人更喜欢使用eval { $foo->isa("thing") }而不是不常见的autobox模块,这也会影响性能。
      【解决方案5】:

      假设您希望能够做的事情的示例是在一个对象方法中,那么您就不必要地偏执了。第一个传递的项目将始终是对适当类(或子类)的对象的引用,或者是类(或子类)的名称。它永远不会是任何其他类型的引用,除非该方法被故意作为函数调用。因此,您可以放心地使用 ref 来区分这两种情况。

      if (ref $_[0]) {
        my $self = shift;
        # called on instance, so do instancey things
      } else {
        my $class = shift;
        # called as a class/static method, so do classy things
      }
      

      【讨论】:

        【解决方案6】:

        没错。对于重载isa 的类,它做错了事。只需使用以下成语:

        if (eval { $obj->isa($class) }) {
        

        它很容易理解并被普遍接受。

        【讨论】:

          【解决方案7】:

          2020 年更新:Perl v5.32 有 class infix operatorisa,可以处理左侧的任何事情。如果 $something 不是对象,则返回 false 且不会爆炸。

          use v5.32;
          
          if( $something isa 'Animal' ) { ... }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-12-22
            • 2010-10-07
            • 1970-01-01
            • 1970-01-01
            • 2016-05-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多