《lua프로그래밍》 독서노트 제7장: 교체기와 범형for

10875 단어

7.1 교체기와closure


'교체기'는 집합의 모든 요소를 두루 훑어보는 메커니즘이다. Lua에서는 보통 교체기를 함수로 표시하고 함수를 한 번도 호출하지 않으면 집합의'다음'요소로 되돌아간다.closure는 교체기에 아주 좋은 지원을 제공합니다. 하나의closure 구조는 보통 두 가지 함수와 관련이 있습니다.closure 자체와closure를 만드는 공장 함수입니다.테이블의 각 요소의 값을 반환하는 간단한 반복기를 작성합니다.
    function value(t)
        local i = 0
        return function() i = i + 1; return t[i] end
    end

이 예에서value는 하나의 공장으로 폐쇄closure로 되돌아옵니다.이 반복기를 사용하여 다음 테이블을 반복합니다.
t = {10, 20, 30}
iter = value(t)
while true do
    local element = iter()
    if element == nil then break end
    print(element)
end

그러나 범용 for를 사용하는 것은 더욱 간단하다. 이것은 바로 교체기를 위해 설계된 것이다.
t = {10, 20, 30}
for val in value(t) do
    print(val)
end

좀 더 복잡한 예를 살펴보겠습니다.
function allwords()
    local line = io.read()
    local pos = 1
    return function()
        while line do
            local s,e = string.find(line, "%w+", pos)
            if s then
                pos = e + 1
                return string.sub(line, s, e)
            else
                line = io.read()
                pos = 1
            end
        end
        return nil
    end
end

for word in allwords() do
    print(word)
end

7.2 범용 for의 의미


앞에서 언급한 교체기는 모두 단점이 하나 있는데, 모든 새로운 순환에 closure를 만들어야 한다는 것이다.범용 for는 순환 과정 내부에 교체기 함수를 저장하는데, 실제로는 3개의 값을 저장한다. 하나는 교체기 함수, 하나는 고정 상태, 하나는 제어 변수이다.일반 for 구문은 다음과 같습니다.
for  in <exp-list> do
    < body >
end

는 쉼표로 구분된 하나 이상의 변수 이름 목록입니다. 은 쉼표로 구분된 하나 이상의 표현식 목록입니다.일반적인 표현식 목록은 교체기 공장에 대한 호출 문구만 있습니다.변수 목록의 첫 번째 요소는 제어 변수입니다.순환 과정 중 이 값은nil이 되지 않습니다. 왜냐하면 이값은nil일 때 순환이 끝나기 때문입니다.for가 하는 첫 번째 일은 in 뒤에 있는 표현식에 대한 값을 구하는 것입니다.이 표현식들은 for에 저장할 수 있는 세 개의 값을 되돌려야 한다. 그것이 바로 교체기 함수, 고정 상태, 변수를 제어하는 초기 값이다.마지막 표현식만 여러 개의 결과를 낼 수 있고 최대 3개의 값을 보존할 수 있는 다중 값과 유사하다.명확하게 말하면 다음과 같은 문장: for var1, …, val_n in < explist > do < block > end 는 다음 코드와 같습니다.
do
    local _f, _s, _var = < explist >
    while true do
        local var_1, ... var_n = _f(s, _var)
        _var = var_1
        if _var = nil then break end
        
    end
end

우리가 간단한 교체기를 사용할 때, 공장은 하나의 교체기 함수만 되돌려주기 때문에, 고정 상태와 제어 변수는nil이다.

7.3 무상태 교체기


무상태 교체기란 자신이 어떤 상태도 보존하지 않는 교체기입니다. 매번 교체할 때마다 for순환은 고정된 상태와 제어 변수로 교체기 함수를 호출하여 다음 요소를 생성합니다.전형적인 예는 바로 ipairs다.ipairs는 다음과 같이 자체 구현됩니다.
local 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

7.4 복잡한 상태를 가진 교체기


동행 교체기는 많은 상태를 저장해야 하지만 for순환은 고정된 상태와 제어 변수만 제공합니다.간단한 해결 방법은 closure를 사용하거나, 교체기에 필요한 모든 상태를 하나의 테이블로 포장하여 고정된 상태에 저장하는 것이다.
local iterator
function allwords()
    local state = {line = io.read(), pos = 1}
    return iterator, state
end

function iterator(state)
    while state.line do
        local s, e = string.find(state.line, "%W+", state.pos)
        if s then
            state.pos = e + 1
            return string.sub(state.line, s, e)
        else
            state.line = io.read()
            state.pos = 1
        end
    end
    return nil
end

가능한 한 무상태 교체기를 작성합니다. 그러면 모든 상태가 for 변수에 저장되며, 순환을 시작할 때 새로운 대상을 만들 필요가 없습니다.그렇지 않으면 closure를 사용해 보아야 합니다. 보통 한 closure가 실행하는 교체기가 한 테이블을 사용하는 교체기보다 효율적이기 때문입니다. 이것은 한 테이블이 한 테이블보다 값이 싸고, 그 다음에 '비국부적인 변수' 를 방문하는 것이 테이블 필드에 접근하는 것보다 빠르기 때문입니다.

7.5 진정한 교체기


실제로 상술한 교체기는 실제 교체를 하지 않았고 진정으로 교체를 하는 것은 for순환이다.그러나 교체기는 매번 교체에 성공한 후의 반환 값을 제공할 뿐'생성기'와 같다.또한 교체기를 만드는 방법은 교체기에서 실제 교체 작업을 하는 것이다.
function allwords(f)
    for line in io.lines() do
        for word in string.gmatch(line, "%W+") do
            f(word)
        end
    end
end

두 종류의 교체기는 대체적으로 같은 비용을 부담하지만, 생성기 스타일의 교체기는 더욱 유연하다.

좋은 웹페이지 즐겨찾기