复制子程序

amo*_*mon 5 perl

我试图将原型应用于子程序的副本,而不修改现有的子程序.即这不行:

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)

避免XY问题:

我的X -Problem是第三方模块定义了一些foo没有原型的功能.明智地使用原型可以使这个功能更加优雅,所以我想创建该子的副本,除了它有一个原型.我不能对foo函数做任何假设- 它也可能是一个XS子程序.

我无法直接设置原型foo,因为我不希望干扰依赖原始行为的其他模块foo.

所以我们到达了我的Y -Problem:如何复制子程序.

nwe*_*hof 6

奇迹功能可能是内部的cv_clone.

你提到过Sub::Clone,它似乎做你想要的.它带有一个基于goto你描述的技巧的纯Perl实现,以及一个调用的XS实现cv_clone.

我找不到包装此内部函数的另一个模块.如果您在安装模块时遇到问题,我建议您打开RT票证.已经存在一个较旧但尚未解决的故障单,因此您可能需要轻推其中一个维护人员.

理想情况下,此功能将是模块的一部分Sub::Util.我们已经有了Scalar::Util,List::Util,Hash::Util,但没有用于子程序.