我认为变量不应该在你打算使用它们之前初始化。它可以更容易地记住变量代表什么,如果它是由消耗它的代码,并且它减少了变量在初始化和正确使用之间被滥用的可能性。
当使用该变量在一个或两个循环内时,会出现问题。然后,初始化的成本会成倍增加,并可能开始影响性能。
在Perl中(或者通常,在适当的情况下),它们是否有任何简洁的技术,允许您将变量的初始化置于循环中,但是只能在第一次传递时初始化?
我想到了类似的东西:
my $variable = undef;
while ($outer_loop) {
while ($inner_loop) {
$variable = $variable || 'initial_value'
}
}
注意:这意味着$variable
不会在循环中重新分配。
现在也许是我,但这看起来有点不雅。
所以,这是我的问题:有没有更简洁的方法来做到这一点,或者我只是需要过度自我并在代码组织方面做出妥协,或者在上面采用那种“不优雅”的解决方案?
答案 0 :(得分:6)
解决评论中的问题(变量在函数中计算):
用于优化此类逻辑的标准技术称为 memoization (该函数)。在其他方法中,Perl具有Memoize
模块,或者您可以自己完成。
use Memoize;
memoize('slow_function');
while ($outer_loop) {
while ($inner_loop) {
my $variable = slow_function(arguments);
}
}
此外,如果函数在整个循环中始终产生100%相同的值(按设计),只需通过在循环之前的语句中初始化变量来执行穷人的memoization。
如果你有一个3页长的循环(例如,在循环之前进行初始化是一个与循环内部相比的可读性问题那么长),你有一个比初始化行的位置更大的编码问题,并且需要首先重新考虑你的代码。
顺便说一句,如果你唯一关心的是在循环之前放置变量是因为它破坏了“这个变量只在这个循环中使用”的可读性上下文,你可以通过以下任一方式轻松解决它:
记录良好的代码 - 相应地命名变量,或者在初始化行中添加注释,或两者都添加。
或者,通过命名类似my $default_value_for_next_loop = long_func();
的变量,并在循环内部实际创建一个从其初始化的本地循环变量:my $loop_var = $default_value_for_next_loop;
另外,就你自己的方法而言($variable = $variable || 'initial_value';
);
我个人觉得这绝对优雅可读,但是!我很确定它实际上比直接$variable = $default_value_for_next_loop;
执行更差,因为它有条件语句而不是直接赋值。但如果没有基准测试,我无法确定。
答案 1 :(得分:4)
是吗?你测量过吗?如果你的当使用该变量在一个或两个循环内时,会出现问题。然后,初始化的成本会成倍增加,并可能开始影响性能。
$variable
在两个循环中都适用于代码,那么我会按如下方式编写循环:
my $variable = 'initial_value';
while ($outer_loop) {
while ($inner_loop) {
# ...
}
}
这样,读者就知道$variable
用于以下代码部分,以及它的初始值是什么。在您的代码段中,读者必须在循环深处的某处找到实际初始值。
此处不太可能存在性能问题,但如果这是一个关键因素,则应始终衡量性能。
答案 2 :(得分:3)
我认为你的指引有点太过分了。阻止滥用变量的最佳方法是延迟它的声明,直到它需要它为止。 (因此将其限制在最小可能的词法范围内。)延迟初始化并不能防止滥用;它只是为某人创造了一个机会,可以使用未定义的值,抢占您自己的初始化,或者将您的变量用于完全不相关的目的。
如果变量需要初始值/默认值,则应尽可能将其作为声明的一部分。这清楚地表明该变量具有起始值。
my $x = 1;
my $y = f($x);
延迟初始化意味着没有初始值。如果没有,或者如果你不能提前确定,那就没关系了,但是你后来偷偷溜过$var //= 'value'
就牺牲了清晰度。
对于需要在循环迭代中保留其值的变量,您必须在循环外声明它们。有时我会在一个额外的块中包装循环,以防止这些变量泄漏到以下代码中:
{
my $i = 5;
for (1 .. 10) {
say $i++;
}
}