2012-10-20 24 views
1

德爾福枚舉的規範MoveNext的是這樣寫的:規範的枚舉器MoveNext函數中是否需要if語句?

function TListEnumerator.MoveNext: Boolean; 
begin 
    Result := FIndex < FList.Count - 1; 
    if Result then 
    Inc(FIndex); 
end; 

這是整個RTL採用的形式,VCL等等。這種形式似乎是普遍在3 黨代碼也。

我認爲它可以更簡單地寫成這樣:

function TListEnumerator.MoveNext: Boolean; 
begin 
    Inc(FIndex); 
    Result := FIndex < FList.Count; 
end; 

有沒有什麼好的理由不能用簡單的形式?


我的推理如下。一旦MoveNext返回FalseCurrent屬性永遠不會再次訪問。 FIndex不在列表的末尾,因爲它不再被使用。在循環中的爲實際執行這樣的:

while Enumerator.MoveNext do 
    Enumerator.Current.DoSomething; 

事實上,它實際上使我更有意義的是FIndex去出界。這意味着如果任何人使用手寫枚舉器代碼,那麼他們將得到範圍檢查錯誤的情況下,Current訪問MoveNext返回False後訪問。

更重要的是,FIndex-1之前的第一個電話MoveNext。這是左邊列表中的一個。在最後致電MoveNext後,返回False的那個,FIndexCount這是不合適的,這是右邊列表中的一個。

+1

在你的版本中,你可以用'FIndex'跳出界限,不是嗎? – TLama

+2

@TLama一旦'MoveNext'返回'False',你就不會調用'GetCurrent'。如果你這樣做,出界就是你想要的。你不想再次獲得最後一個項目。在我看來,這是'FIndex'爲'-1'的初始狀態的鏡像。 –

+0

在我的評論最後,你不*你的原因只是因爲我根本不知道「TListEnumerator」及其意圖。我只是希望在你的弱點... – TLama

回答

3

你假設TListEnumerator僅會在for循環使用。儘管這將是最常見的情況,但如果不是,建議的版本可能會行爲不當。在它已經返回False一次之後再次致電MoveNext就好了。如果您繼續撥打MoveNext,直到它返回True,您必須得到一個無限循環,並且對於您的建議版本,循環不會是無限的,它會在您通過FIndex = MaxInt的情況下終止。

IEnumerator.MoveNext的文檔,Delphi的實現是基於(IIRC,它實際上是在現在死了德爾福.NET第一個可用):

當枚舉數在此位置,後續調用MoveNext也會返回false直到調用Reset。

+0

好的,但Delphi枚舉器中沒有'Reset'。正如它發生的那樣,我只想爲我寫的統計員。 –

+0

這僅僅意味着對於Delphi枚舉器來說,它簡化爲「後續調用MoveNext也返回false」,沒有「until」部分。 :) – hvd

+0

我不太接受適用於其他語言的規則。但是這個規則可能是Delphi MoveNext實現看起來如此的原因。 –

2

純粹從語義上思考,我會說原始版本是正確的。認爲它像一段對話:

Application: Hey, list. Go to the next item. 
List: No, sorry. I can't. 
Application: Oh, allright. 
    <some time later:> 
Application: List, please give me the current item 
List: No problem, here you go. 


Whereas in your suggestion, it would go like this: 


Application, Hey, list. Go to the next item. 
List: No, that's impossible. 
Application: Oh, all right. 
    <some time later:> 
Application: Hi again, List. Give me the current item. 
List: Here you go. 
Application: Thanks, mate. 
    <some time later, when using the item:> 
Application: What the ????! 
+0

問題在於,在第一次會話中,程序會給你一個已經消耗的項目。這將是不好的。而在第二次談話中,WTF是恰當的迴應。據我所知,這兩種情況都不會發生,因爲一旦'MoveNext'返回'False',枚舉器就不會再被詢問當前的項目。我在這裏尋找的是對這種分析的反駁。這不是。 –

+3

如果物品在下一次移動時總是「消耗殆盡」,就會引發這個問題。我想這通常是這種情況,當遍歷列表等,但總是?如果我使用枚舉數來「通過一些數據來回導航」,我想我會更喜歡指針總是有效的。 –

+0

在這種情況下,你可能還會通過設置'FIndex'爲0而不是-1來初始化枚舉器。那是對的嗎? –

1

有趣的問題(+1)。在不瞭解統計員的所有可能用途(或根本不使用統計員)的情況下,乍一看,它的功能在名單的開始和結束之間有所不同,這看起來很奇怪。正如你所說:Current結果在列表索引出界錯誤在一開始,那麼爲什麼不在最後?似乎不一致。

但是仔細想一想:一旦創建了一個枚舉器,無論是誰或者誰,列表的界限都是未知的,所以第一個元素不是也不能被選中。這與限制已知且索引受限的最後行爲相比較。

數據集的功能完全相同,但實施普查員可能會從類似BOFEOF的行爲中受益。