Delphi枚举器中的规范MoveNext如下所示:
function TListEnumerator.MoveNext: Boolean;
begin
Result := FIndex < FList.Count - 1;
if Result then
Inc(FIndex);
end;
这是整个RTL,VCL等中使用的形式。这种形式似乎也广泛存在于3 rd 聚会代码中。
我认为它可以更简单地写成:
function TListEnumerator.MoveNext: Boolean;
begin
Inc(FIndex);
Result := FIndex < FList.Count;
end;
有什么理由不能使用更简单的表格吗?
我的推理如下。 MoveNext
返回False
后,永远不会再访问Current
属性。 FIndex
不在列表的末尾并不重要,因为它永远不会再次使用。 for in循环实际上是这样实现的:
while Enumerator.MoveNext do
Enumerator.Current.DoSomething;
事实上,FIndex
越界越有意义。这意味着如果有人使用手写的枚举器代码,那么在Current
返回MoveNext
后访问False
时,他们将获得范围检查错误。
在第一次调用FIndex
之前,-1
为MoveNext
。这是左边列表中的一个。最后一次调用MoveNext
后,返回False
的{{1}}不适合FIndex
Count
,这是右边列表中的一个。
答案 0 :(得分:3)
您假设TListEnumerator
只会在for
循环中使用。虽然这是迄今为止最常见的情况,但如果不是这样,您建议的版本可能会出错。在MoveNext
已经返回False
之后再次调用MoveNext
就可以了。如果你继续调用True
直到它返回FIndex = MaxInt
,你必须得到一个无限循环,并且使用你建议的版本,循环不会是无限的,它会在你超过{时终止{1}}案例。
请参阅Delphi实现所基于的IEnumerator.MoveNext
文档(IIRC,它实际上首先在现已死的Delphi .NET中提供):
当枚举数位于此位置时,后续对MoveNext的调用也会返回false,直到调用Reset。
答案 1 :(得分: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 ????!
答案 2 :(得分:1)
有趣的问题(+1)。如果不了解普查员的所有可能用途(或者根本不使用它),乍一看,它的功能在列表的开头和结尾之间是不同的,这看起来确实很奇怪。如你所说:Current
在开始时会导致列表索引超出范围错误,那么为什么不在最后呢?似乎不一致。
但是进一步思考它:一旦创建了一个枚举器,无论是什么或者任何人,列表的边界都是未知的,所以第一个元素不是也不能被选中。这与边界已知并且索引限于。
时的行为相比较数据集的功能完全相同,但枚举器的实现可能会受益于BOF
- 和EOF
一样的行为。