假设我有以下代码:
sub level1 {
print "before level 1 \n";
level2();
print "after level 1 \n";
}
sub level2 {
print "before level 2 \n";
level3();
print "after level 2 \n";
}
sub level3 {
print "before level 3 \n";
level4();
print "after level 3 \n";
}
sub level4 {
print "before level 4 \n";
#break_nested();
print "after level 4 \n";
}
print level1();
如果运行此代码,输出将为:
before level 1
before level 2
before level 3
before level 4
after level 4
after level 3
after level 2
after level 1
我想从sub level4直接返回到主包,所以输出应该是:
before level 1
before level 2
before level 3
before level 4
我在cpan上找到了一个名为Sub::Uplevel的模块,但不是我想要的模块。
我还发现Scope::Upper 和Return::MultiLevel ,但不知道如何将它们用于此目的。
我们可以使用来电者知道有多少帧并清除顶部帧或选择特定帧并返回它。
请注意,我不能使用goto标签,因为实际程序分为模块和文件。
答案 0 :(得分:4)
这种控制流程通常是一个非常糟糕的主意。但我们可以使用致命的例外来做到这一点:
use feature 'say';
sub level1 {
say "1 enter";
level2();
say "1 leave";
}
sub level2 {
say "2 enter";
die "I want to break free";
say "2 leave";
}
use Try::Tiny; # better than bare "eval"
say "before try";
try {
level1();
};
say "after try";
输出:
before try
1 enter
2 enter
after try
阅读范围::上层文档,看来你可以用unwind
做同等的事情:
use feature 'say';
use Scope::Upper qw/unwind CALLER/;
sub level1 {
say "1 enter";
level2();
say "1 leave";
}
sub level2 {
say "2 enter";
unwind CALLER 1;
say "2 leave";
}
say "before call";
level1();
say "after call";
输出:
before call
1 enter
2 enter
after call
但请不要使用这些功能,除非这是您的代码的全部要点:否则很难调试问题。
答案 1 :(得分:1)
您可以通过专门为每个子例程添加控制机制来完成此操作。例如,假设我们按如下方式编辑前3个潜艇:
sub level1 {
print "before level 1 \n";
level2() or return;
print "after level 1 \n";
}
sub level2 {
print "before level 2 \n";
level3() or return;
print "after level 2 \n";
}
sub level3 {
print "before level 3 \n";
level4() or return;
print "after level 3 \n";
}
输出仍然相同:
before level 1
before level 2
before level 3
before level 4
after level 4
after level 3
after level 2
after level 1
但是,现在也要编辑level4
子,以表明我们要打破returning
false:
sub level4 {
print "before level 4 \n";
return; # Break nested loops
print "after level 4 \n";
}
print level1();
现在输出:
before level 1
before level 2
before level 3
before level 4
如果要干净地编码,可以在每个子例程的末尾添加显式return 1;
语句。但最终,如果您想要这种类型的功能,只需使用并阅读返回代码即可对其进行编码。