Repeats a series of functions once for each key-value pair in an object.
For Key , Value in Expression
The names of the variables in which to store the key and value at the beginning of each iteration.
When the loop breaks or completes, these variables are restored to their former values.
An expression which results in an object, or a variable which contains an object.
Expression is evaluated only once, before the loop begins. If its result is not an object, execution jumps immediately to the line following the loop's body; otherwise, the object's _NewEnum
method is called to retrieve an enumerator object. At the beginning of each iteration, the enumerator's Next method is used to retrieve the next key-value pair. If Next returns zero or an empty string, the loop terminates.
Although not exactly equivalent to a for-loop, the following demonstrates this process:
_enum := (Expression)._NewEnum() if IsObject(_enum) while _enum.Next(Key, Value) { ... }
Existing key-value pairs may be modified during the loop, but inserting or removing keys may cause some items to be skipped or enumerated multiple times. One workaround is to build a list of keys to remove, then use a second loop to remove the keys after the first loop completes. Note that Object.Delete(first, last)
can be used to remove a range of keys without looping.
A for-loop is usually followed by a block, which is a collection of statements that form the body of the loop. However, a loop with only a single statement does not require a block (an "if" and its "else" count as a single statement for this purpose). The One True Brace (OTB) style may optionally be used, which allows the open-brace to appear on the same line rather than underneath. For example: for x, y in z {
.
As with all loops, Break, Continue and A_Index may be used.
Since Key and Value are passed directly to the enumerator's Next method, the values they are assigned depends on what type of object is being enumerated. For COM objects, Key contains the value returned by IEnumVARIANT::Next() and Value contains a number which represents its variant type. For example, when used with a Scripting.Dictionary object, each Key contains a key from the dictionary and Value is typically 8 for strings and 3 for integers. See ComObjType for a list of type codes.
When enumerating a SafeArray, Key contains the current element and Value contains its variant type.
Enumerator object, Object._NewEnum, While-loop, Loop, Until, Break, Continue, Blocks
; List the key-value pairs of an object: colours := Object("red", 0xFF0000, "blue", 0x0000FF, "green", 0x00FF00) ; The above expression could be used directly in place of "colours" below: for k, v in colours s .= k "=" v "`n" MsgBox s
; List all open Explorer and Internet Explorer windows: for window in ComObjCreate("Shell.Application").Windows windows .= window.LocationName " :: " window.LocationURL "`n" MsgBox windows
/* Class: CEnumerator Generic enumerator object that can be used for iterating over numeric keys. The array must not be modified during iteration, otherwise the iterated range will be invalid. It's possible to define a custom Length() function for array boundaries. If there are missing array members between 1 and max index, they will be iterated but will have a value of "". This means that real sparse arrays are not supported by this enumerator by design. To make an object use this iterator, insert this function in the class definition: _NewEnum() { return new CEnumerator(this) } Source: http://www.autohotkey.com/board/topic/2667-suggestions-on-documentation-improvements/?p=531509 */ ; Iterate over the enumerator For k, v in Test MsgBox k "=" v ; Test class for demonstrating usage class Test { static Data := ["abc", "def", "ghi"] _NewEnum() { return new CEnumerator(this.Data) } } class CEnumerator { __New(Object) { this.Object := Object this.first := true ; Cache for speed. Useful if custom Length functions have poor performance. ; In return, that means that no key-value pairs may be inserted during iteration or the range will become invalid. this.ObjMaxIndex := Object.Length() } Next(ByRef key, ByRef value) { if (this.first) { this.Delete("first") key := 1 } else key++ if (key <= this.ObjMaxIndex) value := this.Object[key] else key := "" return key != "" } }