You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何设置Perl匿名函数原型?解决Mock框架原型不匹配问题

嘿,这个原型不匹配的问题我刚好碰到过,给你分享下解决办法!

问题根源

你遇到的警告“Prototype mismatch: sub ($;$) vs none”,本质是因为原函数FunctionWithPrototype带有($;$)的原型(表示第一个参数必填,第二个可选),但你用来替换的匿名子例程默认没有原型,Sub::Override在替换时检测到原型不一致,就抛出了警告。

解决方案:给匿名子例程设置原型

Perl提供了两种给匿名sub添加原型的方式,都能解决这个问题:

方式1:定义匿名sub时直接指定原型

在写匿名sub的时候,直接在sub后面加上和原函数一致的原型,比如:

# 和原函数原型($;$)保持一致
my $mock_sub = sub ($;$) {
    my ($arg1, $arg2) = @_;
    # 这里写你的mock逻辑,比如返回固定值或者自定义处理
    return "Mocked result: $arg1" . ($arg2 ? " | $arg2" : '');
};

方式2:动态给已存在的匿名sub设置原型

如果已经创建了匿名sub,后期可以用prototype函数为它设置原型:

my $mock_sub = sub {
    my ($arg1, $arg2) = @_;
    return "Dynamic mock: $arg1" . ($arg2 ? " + $arg2" : '');
};
# 关键:设置和原函数相同的原型
prototype($mock_sub) = '($;$)';

结合Test::Mockify和Sub::Override的完整示例

先看你的Hello包示例:

package Hello;

sub FunctionWithPrototype ($;$) {
    my ($arg1, $arg2) = @_;
    return "Original: $arg1" . ($arg2 ? " and $arg2" : '');
}

1;

然后在测试脚本里这样用:

use Test::More;
use Test::Mockify;
use Sub::Override;
use Hello;

# 用方式1替换函数
my $override = Sub::Override->new(
    'Hello::FunctionWithPrototype' => sub ($;$) {
        my ($arg1, $arg2) = @_;
        return "Mocked: $arg1" . ($arg2 ? " | $arg2" : '');
    }
);

is(Hello::FunctionWithPrototype('foo'), 'Mocked: foo', 'Mock without second argument works');
is(Hello::FunctionWithPrototype('foo', 'bar'), 'Mocked: foo | bar', 'Mock with second argument works');

$override->restore;

# 用方式2替换函数
my $dynamic_mock = sub {
    my ($arg1, $arg2) = @_;
    return "Dynamic Mock: $arg1" . ($arg2 ? " + $arg2" : '');
};
prototype($dynamic_mock) = '($;$)';

my $override2 = Sub::Override->new(
    'Hello::FunctionWithPrototype' => $dynamic_mock
);

is(Hello::FunctionWithPrototype('baz'), 'Dynamic Mock: baz', 'Dynamic mock without second argument works');
is(Hello::FunctionWithPrototype('baz', 'qux'), 'Dynamic Mock: baz + qux', 'Dynamic mock with second argument works');

# 也可以直接用Test::Mockify的mock方法
my $Mockify = Test::Mockify->new('Hello');
$Mockify->mock('FunctionWithPrototype', sub ($;$) {
    return "Mockify result: " . join(', ', @_);
});
is(Hello::FunctionWithPrototype('test'), 'Mockify result: test', 'Test::Mockify works with prototype');

done_testing();

这样处理后,不仅原型不匹配的警告会消失,mock的函数还能保持原函数的参数调用规则(比如第一个参数必填,第二个可选),和原函数的行为一致。

内容的提问来源于stack exchange,提问作者Christian Breitkreutz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:44:11