【问题标题】:Explain this witchcraft!!! (in Perl, with Moose and namespace::autoclean)解释这个巫术!!! (在 Perl 中,使用 Moose 和 namespace::autoclean)
【发布时间】:2013-02-04 18:00:08
【问题描述】:

所以这些天我正在处理一个使用 Perl 和 Moose 的项目。我了解 Moose 是建立在 MOP 之上的。我对MOP不是太熟悉,也遇到过不明白的,可以用理论上的解释。这是模块namespace::autoclean的文档:

SYNOPSIS
    package Foo;
    use namespace::autoclean;
    use Some::Package qw/imported_function/;

    sub bar { imported_function('stuff') }

    # later on:
    Foo->bar;               # works
    Foo->imported_function; # will fail. imported_function got cleaned after compilation

所以,在我使用 Moose 之前,您在对象上调用方法的方式是:Perl 解释器会在您的对象被祝福到的包的符号表中查找该方法(然后,如果不是找到了,考虑@ISA继承之类的)。它从包中调用导入函数的方式是:它在包的符号表中查找函数的名称。据我所知,无论哪种方式,这都意味着相同的符号表,所以这种行为应该是不可能的。

我对源的初步检查没有成效。从广义上讲,当使用 Moose、MOP 和 namespace::autoclean 时,这种诡计变得可能有什么不同?

ed. 要特别清楚,如果我将 use namespace::autoclean 替换为

CHECK { undef *Foo::imported_function }

那么文档中描述的Foo->bar; 调用会崩溃,因为Foo->bar 不知道在哪里可以找到imported_function

【问题讨论】:

  • 从长远来看:通过use subs qw/imported_function/; 预先声明会停止自动清洁吗?或者在加载namespace::autoclean之前导入

标签: perl moose symbol-table mop


【解决方案1】:

其实很简单。对于

some_sub()

some_sub 在编译时被解析。对于

$o->some_method()

some_method 在运行时解析。它不能在编译时完成,因为它取决于 $o 的值。

【讨论】:

  • 啊。所以如果我做了sub bar { no strict 'refs'; my $func = "imported_function"; &$func('stuff') },它不会工作。
【解决方案2】:

这里没有什么是非标准的。线

use Some::Package qw/imported_function/;

imported_function 导入到当前包中,所以Foo::imported_functionSome::Package::imported_function 是同一个子例程。这假设 Some::Package 继承自 Exporter 以对符号表进行必要的操作。

调用是方法调用,因此Foo->barFoo::bar('Foo') 相同。这里唯一特别的是,Exporter 中的 import 函数完成的魔法在编译时间结束时被 namespace::autoclean 撤销。

我没有看过这个模块的代码,但是因为一个包的符号表只是一个散列(称为 stash,对于 symbol table hash)在某一时刻保存其状态并在之后恢复它是很容易的。所以我猜namespace::autoclean 在加载符号表时会对其进行快照,并在编译时间结束时恢复该状态。这可以方便地在 CHECK block 中完成,它的行为类似于 BEGIN 块,但在编译结束和运行开始之前执行。

【讨论】:

  • “所以我猜 namespace::autoclean 在加载符号表时会对其进行快照,并在编译结束时恢复该状态。”符号表的编译时操作很简单,但导入方法调用sub bar { imported_function('stuff') } 的解析会在您调用Foo->bar 时发生...在运行时发生 .例如,您会观察到这不起作用:gist.github.com/4708620 显然,这不是对起作用的机制的完整解释。
  • @fennec 当然可以。但是,您undefed 子本身,而不是仅从存储中删除名称→delete ${Foo::}{pseudoimport},它可以工作。 (对于许多名称:delete @{Foo::}{@list_of_names};)。当然,这种野蛮行为也会破坏 any 同名变量)。
  • 好的,这很有趣。那么 Foo::pseudoimport 的代码在 delete ${Foo::}{pseudoimport} 之后在哪里?
  • @fennec 你可以有匿名订阅者:my $anon = sub {...}; 那住在哪里? 不在 中。只要它有引用计数,它就可以访问。名称和值是不同的:my $x = 1; $hash{key} = $x; delete $hash{key} # does $x still have a value?Delete 只是从哈希中删除一个条目,并且不会触及值
  • 嗯。看来您是在说我关于 pseudoimport() 的解析发生在运行时的断言是 false 并且我错了。如果是这样,那就很简单了,可以解释一切。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-18
  • 1970-01-01
  • 1970-01-01
  • 2017-12-04
  • 2014-05-01
  • 2010-09-27
  • 1970-01-01
相关资源
最近更新 更多