수색…
소개
Varargs 는 일반적으로 알려져 있기 때문에 함수가 사양없이 임의의 수의 인수를 취하도록 허용합니다. 이러한 함수에 주어진 모든 인수는 vararg 목록으로 알려진 단일 구조로 패키지됩니다. 루아에서는 ...
로 쓰여 있습니다. select()
함수를 사용하여 주어진 인수의 수와 인수의 값을 추출하는 기본 방법이 있지만 더 많은 고급 사용 패턴이 전체 유틸리티에 구조를 활용할 수 있습니다.
통사론
- ... -이 함수가 가변 인수 함수로 나타나는 인수 목록을 가진 함수를 만듭니다.
- select (what, ...) - 'what'이 1에서 vararg의 요소 수까지의 숫자 인 경우 'what'th 요소를 vararg의 마지막 요소에 반환합니다. 인덱스가 범위를 벗어나면 반환 값은 0이됩니다. 'what'이 문자열 '#'이면 vararg에있는 요소의 수를 반환합니다.
비고
능률
vararg 목록은 언어의 PUC-Rio 구현에서 링크 된 목록으로 구현됩니다. 즉, 색인은 O (n)입니다. 즉, 아래 예제와 같이 select()
사용하여 vararg에있는 요소를 반복하는 것은 O (n ^ 2) 연산입니다.
for i = 1, select('#', ...) do
print(select(i, ...))
end
vararg 목록의 요소를 반복 할 계획이라면 먼저 목록을 테이블에 압축하십시오. 테이블 액세스는 O (1)이므로 반복은 O (n)입니다. 또는 너무 기울이면 고급 사용 섹션에서 foldr()
예제를 참조하십시오. 그것은 재귀를 사용하여 O (n)에서 vararg 목록을 반복합니다.
시퀀스 길이 정의
vararg는 길이가 명시 적으로 전달 된 (또는 계산 된) nils를 존중한다는 점에서 유용합니다. 예를 들어.
function test(...)
return select('#', ...)
end
test() --> 0
test(nil, 1, nil) --> 3
그러나이 동작은 테이블의 동작과 충돌하지만 length 연산자 #
는 'holes'(포함 된 nils)과 함께 작동하지 않습니다. 구멍이있는 테이블의 길이를 계산하는 것은 정의되어 있지 않으므로 의존 할 수 없습니다. 따라서 ...
의 값에 따라 {...}
의 길이를 사용하면 '올바른' 대답이 나오지 않을 수 있습니다. Lua 5.2+에서는 table.pack()
이이 결함을 처리하기 위해 도입되었습니다 (순수 Lua에서는이 함수를 구현 한 함수가 있습니다).
관용적 사용
varargs는 길이가 길어지기 때문에 테이블의 구멍과 관련된 문제를 피하기 위해 시퀀스로 사용합니다. 이는 의도 한 용도가 아니었고 루아의 참조 구현은 최적화되지 않았습니다. 이러한 사용법은 예제에서 살펴 보았지만 일반적으로 눈살을 찌푸리게됩니다.
기초
가변성 함수는 함수 정의의 인수 목록에 ...
생략 부호 구문을 사용하여 작성됩니다.
function id(...)
return
end
이 함수를 id(1, 2, 3, 4, 5)
로 호출하면 ...
(일명 vararg 목록)에는 1, 2, 3, 4, 5
값이 포함됩니다.
함수는 필요한 인수뿐만 아니라 ...
취할 수 있습니다.
function head(x, ...)
return x
end
가변 인수 목록에서 요소를 가져 오는 가장 쉬운 방법은 단순히 변수를 변수에 할당하는 것입니다.
function head3(...)
local a, b, c = ...
return a, b, c
end
select()
또한 요소의 수를 찾을 수의 요소를 추출하는 데 사용할 수 있습니다 ...
간접적으로.
function my_print(...)
for i = 1, select('#', ...) do
io.write(tostring(select(i, ...)) .. '\t')
end
io.write '\n'
end
...
는 {...}
을 사용하여 사용하기 쉽도록 테이블에 압축 할 수 있습니다. 그러면 모든 인수가 테이블의 순차 부분에 놓입니다.
table.pack(...)
은 vararg리스트를 테이블로 table.pack(...)
사용할 수 있습니다. table.pack(...)
의 장점은 반환 된 테이블의 n
필드를 select('#', ...)
값으로 설정한다는 것입니다. 인수 목록에 nils가 포함될 수 있으면 중요합니다 (아래 비고 섹션 참조).
function my_tablepack(...)
local t = {...}
t.n = select('#', ...)
return t
end
vararg 목록은 함수에서 반환 될 수도 있습니다. 결과는 여러 번 반환됩니다.
function all_or_none(...)
local t = table.pack(...)
for i = 1, t.n do
if not t[i] then
return -- return none
end
end
return ... -- return all
end
고급 사용
기본 예제에서 설명한 것처럼 변수 바인딩 된 인수와 변수 인수 목록 ( ...
)을 가질 수 있습니다. 이 사실을 사용하여 다른 언어 (하스켈) 에서처럼 목록을 반복적으로 추출 할 수 있습니다. 다음은이를 활용하는 foldr()
의 구현입니다. 각각의 재귀 호출은 vararg리스트의 헤드를 x
바인드하고 나머지리스트를 재귀 호출로 전달합니다. 이렇게하면 하나의 인수 ( select('#', ...) == 0
)가있을 때까지 목록이 소멸됩니다. 그 후, 각 값은 이전에 계산 된 결과로 함수 인수 f
적용됩니다.
function foldr(f, ...)
if select('#', ...) < 2 then return ... end
local function helper(x, ...)
if select('#', ...) == 0 then
return x
end
return f(x, helper(...))
end
return helper(...)
end
function sum(a, b)
return a + b
end
foldr(sum, 1, 2, 3, 4)
--> 10
이 프로그래밍 스타일을 활용하여 다른 함수 정의 찾을 수 있습니다 여기에 문제 # 8을 통해 이슈 # 3를.
루아의 유일한 관용적 인 데이터 구조가 테이블이다. 시퀀스의 임의의 위치에 nil
이 없으면 테이블 길이 연산자는 정의되지 않습니다. 테이블과는 달리, vararg리스트는 기본 예제와 비고 섹션에 명시된 바와 같이 명시적인 nil
을 고려합니다 (아직 작성하지 않았다면 해당 섹션을 읽으십시오). 거의 작업을하지 않으면 vararg 목록은 테이블이 돌연변이 외에도 수행 할 수있는 모든 작업을 수행 할 수 있습니다. 이것은 vararg리스트를 불변 튜플을 구현하기위한 좋은 후보로 만든다.
function tuple(...)
-- packages a vararg list into an easily passable value
local co = coroutine.wrap(function(...)
coroutine.yield()
while true do
coroutine.yield(...)
end
end)
co(...)
return co
end
local t = tuple((function() return 1, 2, nil, 4, 5 end)())
print(t()) --> 1 2 nil 4 5 | easily unpack for multiple args
local a, b, d = t() --> a = 1, b = 2, c = nil | destructure the tuple
print((select(4, t()))) --> 4 | index the tuple
print(select('#', t())) --> 5 | find the tuple arity (nil respecting)
local function change_index(tpl, i, v)
-- sets a value at an index in a tuple (non-mutating)
local function helper(n, x, ...)
if select('#', ...) == 0 then
if n == i then
return v
else
return x
end
else
if n == i then
return v, helper(n+1, ...)
else
return x, helper(n+1, ...)
end
end
end
return tuple(helper(1, tpl()))
end
local n = change_index(t, 3, 3)
print(t()) --> 1 2 nil 4 5
print(n()) --> 1 2 3 4 5
위와 테이블의 주된 차이점은 테이블이 변경 가능하고 포인터 의미론을 가지고 있다는 점입니다. 튜플에는 이러한 속성이 없습니다. 또한 튜플은 명시 적으로 nil
보유 할 수 있으며 정의되지 않은 길이 연산을 가질 수 있습니다.