一些Perl书籍建议在调用类方法时使用括号,说这有助于防止解析器猜测代码的意图。然而,我所见过的几乎所有Perl代码(包括cpan上的模块)在调用不带参数的方法时很少使用括号。
省略那些括号是正常的吗?还是我应该一直键入它们?
我写了一个小的测试代码来测量调用一个方法时带括号和不带括号之间的差异,它确实显示了一个只有两个方法的类在1%和2%之间的微小差异。我想如果类很大的话,这个差异可能会上升。
下面是我用来进行基准测试的测试脚本:
#!/usr/bin/perl
use Benchmark qw(:all);
{
package Messages;
sub new {
my ($self) = @_;
return bless {}, $self;
}
sub message {
my ($self) = @_;
return "Hello world";
}
sub another {
my ($self) = @_;
return "Another Hello world";
}
}
my $class = Messages->new();
cmpthese(10_000_000, {
'with () ' => sub { $class->message() },
'without () ' => sub { $class->message },
});
这是性能指标评测的结果:
Rate without () with ()
without () 3320053/s -- -1%
with () 3338898/s 1% --
我想,如果应用程序使用数百个模块,每个模块都有数百个方法,这些方法都是在没有括号的情况下调用的,这是否会导致速度上的巨大差异?
如果是的话,为什么每个人都不带括号编码呢?
5条答案
按热度按时间brgchamk1#
1%的差异是系统噪音。两个版本编译成完全相同的字节码,所以它们之间不可能有系统性的差异。使用任何一个使代码更容易阅读的变体。
如果你想看看它编译成什么,你可以这样做:
dgtucam12#
我不确定1%的时间差是否有意义,而且我怀疑您是否能够在真实的程序中测量任何差异。
有些人认为在方法调用的末尾没有
()
看起来更整洁。这是足够的理由。你也会在函数中看到它。对我来说,当我想暗示“这里不需要参数”时,我会尝试这样做。大多数情况下只使用属性getter等。
如果一个方法可以接受可选参数,而它们只是被默认化,那么我宁愿不这样做,这样我就可以区分“不需要参数”和“我没有提供参数,但可以提供”。
svujldwt3#
这里有一些历史。如果你不想读全部,知道
()
解决了一个特殊的解析问题,让Perl知道你使用的是一个子例程而不是一个简单的单词。我倾向于总是使用()
来表示空参数列表。我很好奇你认为哪些Perl书籍提出了这个建议。我是什么?
Perl使用符号来表示名称空间(和访问,但先把它放在一边)。标量有
$
,数组有@
,等等。在Perl 5之前,子例程有&
(沿着crypto context)。这是有区别的Perl 5在子例程调用之前取消了显式的
&
。这允许了另外两种可能性,其中一种现在是不明确的:bareword
可能是一个子程序,但也可能不是,它取决于在使用它之前发生的事情。这个程序编译得很好,但是正如您在反编译中看到的,Perl并不完全知道
foo
是什么:即使子例程定义稍后出现,也会出现同样的问题:
如果你向前声明
foo
将是一个子例程名。现在解析器有一个提示,告诉你该怎么做,即使你从来没有真正定义过这个子例程。一个子例程在你调用它之前不需要定义,Perl是一种动态语言,因此定义可以在以后显示。你也可以向前声明子例程,但在使用之前显示它的定义(虽然大多数人把子程序定义放在程序的最下面,碍事):数量
关于Perl还有另外一件事要知道。你可以在子例程调用中去掉括号,Perl会试图判断下一个标记是否是它的参数。
考虑一个
print
,它有一个参数列表,所有这些都成为print
的参数:但是有些东西需要一定数量的参数,
rand
知道它只需要一个参数,以前有4
的地方,现在有rand
的结果,5
仍然来自5
的参数:对于许多人来说,使用括号来表示读者Perl已经知道的内容更容易阅读:
现在考虑一些参数范围的函数,比如
split
,其中有要使用的模式、目标字符串和最大项数,但所有这些参数都是可选的。现在,我们来看一下,我们打算如何处理
split
?事实证明这是一个陷阱,因为split
抱怨太多参数:括号解决了以下问题:
或者,您可能希望处理
$_
:这看起来像是一个愚蠢的案例,但更复杂的例子归结为一件事。
关于方法
Perl方法总是需要用括号将非零参数列表括起来:
顺便说一句,Raku有一个方法冒号,可以把它后面的所有内容都作为参数。我一开始并不喜欢这个方法,但现在我在Perl 5中怀念它:
Perl不要求在方法的零参数周围使用括号,因此以下两种方法都可以:
但是,在
->
后面的是方法,参数放在括号里,没有猜测。正在收尾
但是,你知道Perl 4有这个
&
,不使用括号做了奇怪的默认参数的事情,所以你用()
来做空参数列表。而且,你要记住,有长范围的影响。所以有些人用()
来表示他们想要什么。其他人更舒服地知道Perl要做什么。由此可见,有些人喜欢在任何地方都做同样的事情,所以即使一个案例可能不需要,因为他们在其他地方做,即使不需要,他们也会做。其他人则不那么在意。
在Learning Perl中,我们知道你会看到很多不同的东西,所以我们展示了很多不同的东西。有你写的代码,但也有你没有写但必须读的代码。
ldxq2e6h4#
因为你可以。真的。我认为。Perl允许这么多,人们正在使用它。有时是好的,因为你可以在短序列中写非常复杂的东西,有时是坏的,因为它经常变得复杂(特别是对Perl的新手)。
这也取决于你的程序做什么。区别应该只是在编译时间(我假设)。通常情况下,编译时间是整个应用程序生命周期的一小部分,在那里它并不那么重要。
webghufk5#
我认为你的测量中存在系统性误差。当我运行你的代码时,
without ()
每次都优于with ()
。但当我在cmpthese
中使用相同长度的字符串时,例如:我得到了这些(相当预期的)结果:
所以我认为这只是关于最佳实践。