Lua 튜토리얼 (5): 교체기와 일반 for

5707 단어
1. 교체기 및 Closure:
Lua에서, 교체기는 보통 함수로, 매번 함수를 호출할 때마다, 즉 집합의 '다음' 요소를 되돌려줍니다.모든 교체기는 매번 성공적으로 호출될 때마다 상태를 유지해야만 그것이 있는 위치와 다음에 반복될 때의 위치를 알 수 있다.이 점에서 Lua에서 closure 메커니즘은 이 문제에 대해 언어적 보장을 제공하는데 다음과 같은 예를 들 수 있다.
 
  
function values(t)
    local i = 0
    return function()
        i = i + 1
        return t[i]
    end
end
t = {10, 20, 30}
it = values(t)
while true do
    local element = it()
    if element == nil then
        break
    end
    print(element)
end
-- foreach ( for)
t2 = {15, 25, 35}
for element in values(t2) do
    print(element)
end
-- :
--10
--20
--30
--15
--25
--35

위의 응용 예시를 보면while 방식에 비해 범형for 방식은 더욱 뚜렷한 실현 논리를 제공했다.루아는 내부에 교체기 함수를 저장하고, 교체할 때마다 이 은밀한 내부 교체기를 호출하여 교체기가 nil로 돌아올 때까지 순환을 끝내기 때문이다.
    2. 범용 for의 의미:
상기 예시된 교체기는 순환할 때마다 새로운closure 변수를 만들어야 한다는 뚜렷한 단점이 있습니다. 그렇지 않으면 첫 번째 교체가 성공한 후에 이closure를 새로운 for 순환에 사용하면 바로 종료됩니다.
여기서 우리는 먼저 Lua 중범형(for)의 메커니즘을 상세하게 설명한 다음에 무상태 교체기의 예를 제시하여 우리의 이해를 편리하게 한다.만약 우리의 교체기가 무상태 교체기로 실현된다면, 매번의 범용 (for) 을 위해 새로운 교체기 변수를 다시 설명할 필요가 없다.범용(for)의 구문은 다음과 같습니다.
 
  
    for in do
       
    end
 

이해하기 편리하도록, 우리는 실제 응용에서 일반적으로 하나의 표현식 (expr) 만을 포함하기 때문에, 간단하게 보면, 이 설명은 표현식 목록이 아니라 하나의 표현식만 포함할 것이다.지금 우리는 먼저 표현식의 원형과 실례를 제시한다. 예를 들어 다음과 같다.
 
  
function ipairs2(a)
    return iter,a,0
end

이 함수는 3개의 값을 되돌려줍니다. 첫 번째는 실제 교체기 함수 변수이고, 두 번째는 고정 대상입니다. 여기서 우리는 반복되는 용기로 이해할 수 있습니다. 세 번째 변수는iter () 함수를 호출할 때 전달되는 초기 값입니다.
다음은 iter () 함수의 실현을 살펴보자. 예를 들어
 
  
local function iter(a, i)
    i = i + 1
    local v = a[i]
    if v then
        return i, v
    else
        return nil, nil
    end
end

교체기 함수iter () 에서 두 개의 값을 되돌려줍니다. 각각 테이블의 키와value에 대응합니다. 그 중에서 키 (되돌려주는 i) 가 nil이면 범용 (for) 은 이번 교체가 끝났다고 생각할 것입니다.다음은 실제 사용 사례를 살펴보겠습니다. 예를 들어 다음과 같습니다.
 
  
function ipairs2(a)
    return iter,a,0
end


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

a = {"one","two","three"}
for k,v in ipairs2(a) do
    print(k, v)
end
-- :
--1       one
--2       two
--3       three


이 예의 범용 (for) 쓰기 방법은while 순환을 기반으로 하는 다음과 같은 방식으로 전개될 수 있습니다.
 
  
local function iter(a, i)
    i = i + 1
    local v = a[i]
    if v then
        return i, v
    else
        return nil, nil
    end
end

function ipairs2(a)
    return iter,a,0
end

a = {"one","two","three"}
do
    local _it,_s,_var = ipairs2(a)
    while true do
        local var_1,var_2 = _it(_s,_var)
        _var = var_1
        if _var == nil then  -- , nil。
            break
        end
        print(var_1,var_2)
    end
end
-- 。


   
3. 무상태 교체기의 예:
이곳의 예는 체인 테이블을 옮겨다니는 교체기를 실현할 것이다.
 
  
local function getnext(list, node)  -- 。
    if not node then
        return list
    else
        return node.next
    end
end

function traverse(list)  -- (for) expression
    return getnext,list,nil
end

-- 。
list = nil
for line in io.lines() do
    line = { val = line, next = list}
end

-- (for) 。
for node in traverse(list) do
    print(node.val)
end


여기서 사용하는 기교는 체인 테이블의 두결점을 고정 상태(traverse가 되돌아오는 두 번째 값)로 하고 현재 노드를 제어 변수로 하는 것이다.교체기 함수 getnext () 를 처음 호출할 때, node는nil이기 때문에 함수는list를 첫 번째 결점으로 되돌려줍니다.후속 호출에서 node가 더 이상 nil이 아니기 때문에 교체기가 node로 되돌아옵니다.next, 체인 테이블 끝부분의 nil 결점을 되돌릴 때까지 범용 (for) 은 교체기의 반복이 끝났다는 것을 판단합니다.
마지막으로 설명해야 할 것은traverse() 함수와list 변수는 반복적으로 호출할 수 있으며 새로운closure 변수를 만들 필요가 없다는 것이다.이것은 주로 교체기 함수 (getnext) 가 무상태 교체기로 실현되기 때문이다.
    4. 복잡한 상태의 교체기:
위에서 소개한 교체기 구현에서 교체기는 많은 상태를 저장해야 하지만 범형(for)은 고정된 상태와 제어 변수만 제공하여 상태의 저장에 사용한다.가장 간단한 방법은closure를 사용하는 것이다.물론 우리는 모든 정보를 하나의 테이블에 봉하여 고정된 상태의 대상으로 교체기에 전달한다.항정 상태 변수 자체는 항정이다. 즉, 교체 과정에서 다른 대상으로 바뀌지 않는다. 그러나 이 대상에 포함된 데이터의 변화 여부는 교체기의 실현에 달려 있다.현재로서는 테이블 형식의 고정 대상이 모든 교체기에 의존하는 정보를 포함하고 있기 때문에, 교체기는 일반 (for) 이 제공하는 두 번째 인자를 완전히 무시할 수 있다.다음은 다음과 같은 코드를 참조하여 다음과 같은 예를 보여 드리겠습니다.
 
  
 local iterator
function allwords()
    local state { line = io.read(), pos = 1 }
    return iterator, state
end
--iterator
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
 

좋은 웹페이지 즐겨찾기