English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Lua 이터레이터

이터레이터(iterator)는 객체로서 표준 템플릿 라이브러리 컨테이너의 일부나 전체 요소를 탐색할 수 있습니다. 각 이터레이터 객체는 컨테이너 내의 명확한 주소를 대표합니다。

Lua에서 이터레이터는 포인터 타입을 지원하는 구조체로, 셋의 각 요소를 탐색할 수 있습니다。

제네릭 for 이터레이터

제네릭 for 이터레이터는 자신 내부에서 이터레이션 함수를 저장하며 실제로는 세 가지 값을 저장합니다: 이터레이션 함수, 상태 상수, 제어 변수。

제네릭 for 이터레이터는 셋의 키를 제공합니다/value 값에 대해 다음과 같은 문법 형식이 있습니다:

for k, v in pairs(t) do
    print(k, v)
end

위 코드에서 k, v는 변수 목록입니다;pairs(t)는 표현식 목록입니다。

다음 예제를 확인하세요:

array = {"Google", "w3codebox"}
for key, value in ipairs(array) 
do
   print(key, value)
end

以上代码执行输出结果为:

1  Google
2  w3codebox

以上示例中我們使用了 Lua 默认提供的迭代函数 ipairs。

下面我們看看泛型 for 的執行過程:

  • 首先,初始化,計算 in 後面表達式的值,表達式應該返回泛型 for 需要的三个值:迭代函数、状态常量、控制变量;与多值赋值一样,如果表达式返回的结果个数不足三个会自动用 nil 补足,多出部分会被忽略。

  • 第二,將狀態常數和控制變數作為參數調用迭代函數(注意:對於 for 結構來說,狀態常數沒有用途,僅僅在初始化時獲取他的值並傳遞給迭代函數)。

  • 第三,將迭代函數返回的值賦給變數列表。

  • 第四,如果返回的第一個值為 nil 循環結束,否則執行循環體。

  • 第五,回到第二步再次調用迭代函數

在 Lua 中我們常常使用函數來描述迭代器,每次調用該函數就返回集合的下一個元素。Lua 的迭代器包含以下兩種類型:

  • 無狀態的迭代器

  • 다중 상태 이터레이터

無狀態的迭代器

無狀態的迭代器是指不保留任何狀態的迭代器,因此在那個循環中我們可以利無狀態迭代器避免創建閉包花費額外的代價。

每一次迭代的函數都是用兩個變數(狀態常數和控制變數)的值作為參數被調用,一個無狀態的迭代器只利用這兩個值可以獲取下一個元素。

這種無狀態迭代的典型簡單的實例是 ipairs,它遍歷數組的每一個元素。

以下示例我們使用了一個簡單的函數來實現迭代器,實現數字 n 的平方:

function square(iteratorMaxCount, currentNumber)
   if currentNumber < iteratorMaxCount
   then
      currentNumber = currentNumber+1
   return currentNumber, currentNumber*currentNumber
   end
end
for i, n in square,3,0
do
   print(i, n)
end

위 예제의 출력 결과는 다음과 같습니다:

1    1
2    4
3    9

迭代的狀態包括被遍歷的表(循環過程中不會改變的狀態常數)和當前的索引下標(控制變數),ipairs 和迭代的函數都很簡單,我們在 Lua 中可以這樣實現:

function iter(a, i)
    i = i + 1
    local v = a[i]
    if v then
       return i, v
    end
end
 
function ipairs(a)
    return iter, a, 0
end

Lua가 ipairs(a)를 호출하여 루프를 시작할 때, 그는 세 가지 값을 얻습니다: 이터레이션 함수 iter, 상태 상수 a, 제어 변수 초기 값 0; 그런 다음 Lua가 iter(a,0)를 호출하여 반환 1, a[1](除非 a[1=nil); 두 번째 이터레이션 호출 iter(a,1] 반환 2, a[2]……첫 번째 nil 요소까지.

다중 상태 이터레이터

대부분의 경우 이터레이터는 간단한 상태 상수와 제어 변수보다 많은 상태 정보를 저장해야 합니다. 가장 간단한 방법은 클로저를 사용하는 것이며, 또 하나의 방법은 모든 상태 정보를 테이블에 포장하는 것입니다. 테이블을 이터레이터의 상태 상수로 사용하면 모든 정보를 테이블에 저장할 수 있으며, 따라서 이터레이션 함수는 두 번째 매개변수가 필요하지 않습니다.

다음 예제에서는 우리가 자신의 이터레이터를 생성했습니다:

array = {"Google", "w3codebox"}
function elementIterator(collection)
   local index = 0
   local count = #collection
   -- 클로저 함수
   return function ()
      index = index + 1
      if index <= count
      then
         --  이터레이터의 현재 요소를 반환합니다
         return collection[index]
      end
   end
end
for element in elementIterator(array)
do
   print(element)
end

위 예제의 출력 결과는 다음과 같습니다:

Google
w3codebox

위 예제에서는 elementIterator 내에서 클로저 함수가 사용되어 셋의 크기를 계산하고 각 요소를 출력하는 것을 볼 수 있습니다.