我正在阅读Code Complete 2,其中提到的要点之一是关于创建子例程,即使对于那些看起来太简单而无法拥有自己的子例程的操作,以及这有什么帮助。
我知道我可以使用关键字在 C 和 C++ 中内联函数。inline
但是我从来没有遇到过在 Perl 中内联子程序的方法。
有没有办法告诉 Perl 解释器内联子例程调用(或者为什么不内联)?
我正在阅读Code Complete 2,其中提到的要点之一是关于创建子例程,即使对于那些看起来太简单而无法拥有自己的子例程的操作,以及这有什么帮助。
我知道我可以使用关键字在 C 和 C++ 中内联函数。inline
但是我从来没有遇到过在 Perl 中内联子程序的方法。
有没有办法告诉 Perl 解释器内联子例程调用(或者为什么不内联)?
常量子程序,即具有空原型和常量返回值的子程序,是内联的。这就是常量pragma 定义常量的方式:
sub five() { 5 }
如果在第一次使用之前看到它,它将被内联。
否则,Perl 允许在运行时动态地重新定义子例程,因此内联是不合适的。
对于在给定相同输入的情况下始终返回相同值的子例程,您可以使用memoization。
Programming Perl 的第 13 章提供了一些关于perl
.
这称为常量折叠。常量折叠不限于简单的情况,例如在编译时将 2**10 转换为 1024。它还解析函数调用——满足第 6 章“子程序”中“内联常量函数”部分标准的内置子程序和用户声明的子程序。让人想起 FORTRAN 编译器对自己的内在函数的臭名昭著的了解,Perl 也知道在编译期间要调用哪些自己的内置函数。这就是为什么如果您尝试获取 0.0 的日志或负常数的 sqrt,您将导致编译错误,而不是运行时错误,并且解释器根本不会运行。
另请参阅perldoc perlguts。
你可以看到自己不断折叠的效果:
#!/usr/bin/perl
use strict; use warnings;
sub log_ok () { 1 }
if ( log_ok ) {
warn "log ok\n";
}
perl -MO=Deparse t.pl
输出:
子 log_ok () { 1 } 使用警告; 使用严格的“参考”; 做 { 警告“登录正常\n” }; t.pl 语法OK
在这里,常量折叠导致用块替换if
块,do
因为编译器知道它log_ok
总是会返回一个真值。另一方面,与:
#!/usr/bin/perl
use strict; use warnings;
sub log_ok () { 0.5 > rand }
if ( log_ok ) {
warn "log ok\n";
}
解析输出:
子 log_ok () { 使用警告; 使用严格的“参考”; 0.5 > 兰特; } 使用警告; 使用严格的“参考”; 如果(log_ok){ 警告“登录正常\n”; } t.pl 语法OK
编译器C
可能已将 替换if (log_ok)
为if ( 0.5 > rand )
。perl
不这样做。
Perl 只允许内联常量函数。从perldoc perlsub:
具有 () 原型的函数是内联的潜在候选者。如果优化和常量折叠后的结果是常量或没有其他引用的词法范围标量,那么它将用于代替没有 & 的函数调用。
我没有尝试过这些,但如果你有时间,你可以试试
它们都是源过滤器,因此您必须检查您在性能方面的投资回报。最后一个其实是对cpanratings的评论。(忽略 Dan Dascalescu 对 Perl 模块“空域”进行规范的尝试。)
--实际上,最后一个Filter::Macro
使用Filter::Simple::Compile
(反过来使用Module::Compile
)编译例程,因此这可能在其他源过滤器方法之上执行。但适用于源过滤器的标准警告。
编写 Perl 时可能不应该考虑速度。来吧,让事情发挥作用。如果稍后的分析表明您由于调用了很多简单函数而花费了大量时间,那么您自己内联该函数。