2011-01-13 26 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++; 
    } 
} 
相關問題