2011-01-13 55 views
2

我订阅的想法是,变量不应该被初始化,直到你要使用它们。它使得更容易记住变量代表的是代码是否会消耗变量,并且减少了变量在初始化和正确使用之间被误用的可能性。如何保持良好的代码组织而不牺牲性能?

当使用该变量在一个循环或两个循环内时出现问题。然后,初始化成本增加,它可能开始影响性能。

在Perl的(或一般,酌情而定),是他们的任何整洁的小技巧,让你把一个循环内的变量的初始化,但是使得它只被第一遍初始化?

我想象的是这样的:

my $variable = undef; 
while ($outer_loop) { 
    while ($inner_loop) { 
     $variable = $variable || 'initial_value' 
    } 
} 

注:言下之意是,$variable不是在循环中重新分配。

现在也许是我,但这似乎有点不雅。

所以,这里是我的问题:是否有一个更好的方法来做到这一点,或者我只是需要克服自我和妥协的代码组织,或吸了上面的'不雅'的解决方案?

回答

6

为了解决问题,在您的评论(变量计算的函数):

  • 优化这种想要逻辑的标准技术被称为memoization的(即功能)。在其他方法中,Perl有Memoize模块,或者你可以自己做。

    use Memoize; 
        memoize('slow_function'); 
        while ($outer_loop) { 
         while ($inner_loop) { 
          my $variable = slow_function(arguments); 
         } 
        } 
    
  • 此外,如果功能总是在整个循环产生100%相同的值(由设计),简单地通过在之前的循环中的语句初始化变量做差芒记忆化。

    如果你有一个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;,因为它有一个条件声明,而不是一个直接的任务。但如果没有基准测试,我无法确定。

4

存在的问题时,如果本使用该变量的是一个或两个环的内侧。然后,初始化成本增加,它可能开始影响性能。

是吗?你测过它了吗?如果您$variable适用于代码贯穿两个环,那么我会写出如下的循环:

my $variable = 'initial_value'; 
while ($outer_loop) { 
    while ($inner_loop) { 
     # ... 
    } 
} 

这样一来,读者知道$variable在下面的代码段使用,以及它的初始值是。在您的代码段,读者必须去找到实际初期值的环深的地方。

有不太可能是这里的性能问题,但你应该总是衡量性能,如果这是一个关键因素。

+0

它确实...它不是一个简单的赋值;该值通过函数调用生成。我同意,一般来说,衡量价值生成的成本可能会更好,看看它是否有意义,但我仍然有兴趣查看是否还有其他技术可以/通常/应用 – Dancrumb 2011-01-13 19:04:32

+1

多久会你期望在没有足够进入循环来调用你的初始化函数的情况下,接近那个代码片断*。在循环顶部初始化变量的代码仍然按照不同的顺序执行相同的工作量。而且,您不必每次都通过内部循环来检查变量是否已初始化。 – 2011-01-13 19:18:36

3

我认为你的指导思想有点过分。停止滥用变量的最佳方法是将其延迟声明,直到需要之前。 (因此将其限制为最小可能的词法范围。)延迟初始化不会防止滥用;它只是为某人使用一个未定义的值创造机会,以自己的优先权进行抢占,或者将您的变量用于完全不相关的目的。

如果一个变量需要一个初始值/默认值,那么应尽可能在声明中完成。这表明该变量具有初始值。

my $x = 1; 
my $y = f($x); 

延迟初始化意味着没有初始值。如果没有一个,或者如果你不能提前确定它,那很好,但是你在后面偷偷摸摸地做出了牺牲清晰度。

对于需要在循环迭代中保留其值的变量,您必须在循环之外声明它们。有时我会将循环封装在一个额外的块中,以防止这些变量泄漏到以下代码中:

{ 
    my $i = 5; 
    for (1 .. 10) { 
     say $i++; 
    } 
} 
相关问题