我试图将原型应用于子程序的副本,而不修改现有的子程序.即这不行:
use Scalar::Util 'set_prototype';
sub foo {};
*bar = \&foo;
set_prototype(\&bar, '$'); # also modifes "foo"
Run Code Online (Sandbox Code Playgroud)
我想要实现的目标可以通过以下方式完成goto &sub:
sub foo {};
sub bar($) {
goto &foo;
}
Run Code Online (Sandbox Code Playgroud)
但是,这会引入不必要的开销,我并不热衷于此.因此我的问题是:有没有办法制作子程序(CV)的(浅)副本,这样设置副本的原型不会影响原件?就是这样的
use Scalar::Util 'set_prototype';
sub foo {};
*bar = magical_cv_copy(\&foo);
set_prototype(\&bar, '$'); # does not modify "foo"
Run Code Online (Sandbox Code Playgroud)
我看了一下Sub:Clone,但它看起来已经过时了,不会强制安装在我的系统上.我不想为此编写XS代码.
use strict;
use warnings;
use Test::More tests => 7;
use Scalar::Util qw/refaddr set_prototype/;
sub foo {
my ($x) = @_;
return 40 + $x;
}
*bar = then_a_miracle_occurs(\&foo);
ok not(defined prototype \&foo), 'foo has no prototype';
ok not(defined prototype \&bar), 'bar has no prototype';
isnt refaddr(\&foo), refaddr(\&bar), 'foo and bar are distinct';
set_prototype \&bar, '$';
ok not(defined prototype \&foo), 'foo still has no prototype';
is prototype(\&bar), '$', 'bar has the correct prototype';
is foo(2), 42, 'foo has correct behavior';
is bar(2), 42, 'bar has correct behavior';
sub then_a_miracle_occurs {
my ($cv) = @_;
# what goes here?
# return sub { goto &$cv }
}
Run Code Online (Sandbox Code Playgroud)
我的X -Problem是第三方模块定义了一些foo没有原型的功能.明智地使用原型可以使这个功能更加优雅,所以我想创建该子的副本,除了它有一个原型.我不能对foo函数做任何假设- 它也可能是一个XS子程序.
我无法直接设置原型foo,因为我不希望干扰依赖原始行为的其他模块foo.
所以我们到达了我的Y -Problem:如何复制子程序.
奇迹功能可能是内部的cv_clone.
你提到过Sub::Clone,它似乎做你想要的.它带有一个基于goto你描述的技巧的纯Perl实现,以及一个调用的XS实现cv_clone.
我找不到包装此内部函数的另一个模块.如果您在安装模块时遇到问题,我建议您打开RT票证.已经存在一个较旧但尚未解决的故障单,因此您可能需要轻推其中一个维护人员.
理想情况下,此功能将是模块的一部分Sub::Util.我们已经有了Scalar::Util,List::Util,Hash::Util,但没有用于子程序.