perl - mro、goto 和 set_subname 如何交互?

标签 perl goto method-resolution-order perlguts

这是一个关于 mro.pm 以及与 set_subnamegoto 相互作用的复杂问题

在解决问题时,我认为我的误解的核心与 mro.pm 的工作方式有关 - 特别是关于 set_subname

这三种结构有什么区别,

  1. 简单调用set_subname

    *Foo::bar = set_subname( 'Foo::bar', $codeRef );
    
  2. 包装set_subname的匿名子

    *Foo::bar = sub {
      my $codeRef2 = set_subname('Foo::bar', $codeRef);
      goto $codeRef2
    };
    
  3. 使用 set_subname 设置名称的匿名子

    *Foo::bar = set_subname(
      'Foo::bar',
      sub { goto $codeRef }
    );
    

具体来说,Mojo 测试套件在将匿名子应用到 Mojo::Utils's monkey_patch 时会因这些修改而失败。针对 t/mojo/websocket_proxy.t 运行上述两个变体,

  • 使用 2(第二个)选项我有

    *{"${class}::$k"} = sub {                                                                                                                          
      my $cr = set_subname("${class}::$k", $patch{$k});                                                                                                
      goto $cr;                                                                                                                                        
    }; 
    

    我明白了

    Mojo::Reactor::Poll: Timer failed: Can't locate object method "send" via package "Mojo::Transaction::HTTP" at t/mojo/websocket_proxy.t line 66.
    
  • 有了 3(第三个)选项,

    *{"${class}::$k"} = set_subname("${class}::$k", sub { goto $patch{$k} })
    

    我明白了

    No next::method 'new' found for Mojolicious::Routes at /usr/lib/x86_64-linux-gnu/perl/5.28/mro.pm line 30.
    

显然,第一个版本可以工作(来 self 链接的代码),问题是为什么其他两个变体给我带来不同的错误(尤其是第二个变体)以及那里发生了什么 - 为什么它们不工作?

最佳答案

您的第二个选项不起作用,因为您用作包装器的子组件与内部子组件的原型(prototype)不匹配。 monkey_patch 不仅用于方法,而且这改变了一些函数的解析方式。特别是,Mojo::Util::steady_time 具有空原型(prototype),并且通常在不使用括号的情况下调用。

*{"${class}::$k"} = Sub::Util::set_prototype(
  Sub::Util::prototype( $patch{$k} ),
  Sub::Util::set_subname(
    "${class}::$k",
    sub {
      my $cr = Sub::Util::set_subname("${class}::$k", $patch{$k});
      goto $cr;
    }
  )
);

第三个构造不起作用,因为您正在使用 goto 从调用堆栈中删除重命名的包装器子程序,只留下没有名称的内部子程序。这会破坏 next::method 查找正确方法名称的能力。

关于perl - mro、goto 和 set_subname 如何交互?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58677042/

相关文章:

php - 在函数 php 中使用 goto

python - python的多重继承

django add_to_class() 使模型继承/MRO 工作出错

python-3.x - python3 super 不适用于 PyQt 类

perl - SQLite十进制标记

regex - 更改特定字母后的所有出现位置

regex - 如何使用Linux命令工具去除字符串开头和结尾的数字?

c - 转到内部开关盒工作异常

linux - 包外壳 : System commands doesn't work with Centos 7. 4

c - 如何让 GDB 跳出循环?