# For 循环 [AHK_L 59+]

对对象中的每对键值对重复执行一系列命令.

    For Key , Value in Expression

## 参数

Key(键)

  在每次重复开始时用来保存键的变量名称.

Value(值)

  保存与当前键关联的值的变量名.

Expression(表达式)

  结果为对象的表达式或包含对象的变量.

## 备注

只在循环开始前计算一次 表达式. 如果其结果不是对象, 则立即跳转到循环体后面的语句执行; 否则, 调用对象的 `_NewEnum()` 来获取 枚举器 对象. 每次重复开始时, 使用枚举器的 Next() 方法获取下一个键值对. 如果 Next() 返回零, 则循环终止.

尽管不完全等同于 for 循环, 不过下面演示了近似于它的循环过程:

    _enum := (Expression)._NewEnum()
    if IsObject(_enum)
        while _enum.Next(Key, Value)
        {
            ...
        }

现有的键值对可以在循环中修改, 但插入或移除键可能导致一些项目被跳过或枚举多次. 一种解决方法是建立待移除的键列表, 在首个循环结束后使用第二个循环来移除这些键. 请注意使用 `Object.Remove(first, last)` 可以直接移除键的范围而不需要循环.

for 循环后通常跟着区块, 这是构成循环 体 的语句的集合. 不过, 在单语句的循环中可以不使用区块(用于此目的时 "if" 与其相匹配的 "else" 一起被视为单语句). 可以使用 One True Brace(OTB) 风格, 这样允许左大括号与在同一行而不是在其下面一行. 例如: `for x, y in z {`.

和所有的循环一样, 循环中可以使用 Break, Continue 和 A_Index.

## COM 对象

因为 Key 和 Value 被直接传递给枚举器的 Next() 方法, 所以它们的值取决于被枚举的对象类型. 对于 COM 对象, Key 包含由 IEnumVARIANT::Next() 返回的值, 而 Value 包含了表示其变量类型的数字. 例如, 用于 Scripting.Dictionary 对象时, 每个 Key 包含字典中的键而 Value 通常为 8(对于字符串) 和 3(对于整数). 请参阅 ComObjType() 了解类型代码表.

[v1.0.96.00+]: 枚举 SafeArray 时, Key 包含了当前元素而 Value 包含其变量类型.

## 相关

枚举器对象, Object._NewEnum(), While 循环, Loop, Until, Break, Continue, 区块

## 示例

列出对象中的键值对.

    colours := Object("red", 0xFF0000, "blue", 0x0000FF, "green", 0x00FF00)
    ; 上面的表达式可以直接代替下面的 "colours":
    for k, v in colours
        s .= k "=" v "`n"
    MsgBox % s

列出所有的资源管理器和 Internet Explorer 窗口, 使用 Shell 对象.

    for window in ComObjCreate("Shell.Application").Windows
        windows .= window.LocationName " :: " window.LocationURL "`n"
    MsgBox % windows

Class: CEnumerator

提供一个可用于遍历数值键的通用枚举器对象. 在循环期间不能修改数组, 否则迭代的范围将无效. 可以定义自己的 MaxIndex() 函数来表示数组边界. 如果在 1 和最大索引间有缺失的数组成员, 仍会循环到它们但值为空. 这意味着这个枚举器不支持实际的稀疏数组. 来源: 改善文档的建议

    /*
    Class: CEnumerator
    要在对象能使用这种循环, 请在它的类定义中插入这个函数:

        _NewEnum()
        {
        	return new CEnumerator(this)
        }
    */

    ; 对枚举器进行循环
    For k, v in Test
    	MsgBox %k%=%v%

    ; 用于演示的测试类
    class Test
    {
    	static Data := ["abc", "def", "ghi"]

    	_NewEnum()
    	{
    		return new CEnumerator(this.Data)
    	}
    }

    class CEnumerator
    {
    	__New(Object)
    	{
    		this.Object := Object
    		this.first := true
    		; 加速的缓存. 当 MaxIndex() 函数性能差时用得上.
    		; 副作用是在循环时不能插入键值对, 否则区间是错误的.
    		this.ObjMaxIndex := Object.MaxIndex()
    	}

    	Next(ByRef key, ByRef value)
    	{
    		if (this.first)
    		{
    			this.Remove("first")
    			key := 1
    		}
    		else
    			key ++
    		if (key <= this.ObjMaxIndex)
    			value := this.Object[key]
    		else
    			key := ""
    		return key != ""
    	}
    }

dftg