[Rust] 반복자에게 할 일 더해주기 - Iterator adapters
다른 Iterator
(a.k.a 반복자)를 받아 새로운 반복자를 반환하는 함수를 iterator adapter라고 부른다. adapter라는 이름은 GoF의 디자인 패턴 중 하나인 adapter pattern에서 온 말이라고 한다. 그런데 실제로는 adapter pattern보다는 decorator pattern에 해당하기 때문에 이름을 신경쓰면 용도를 헷갈릴 수 있다. 그러니 이름에 대해서는 크게 신경 쓰지 않는 것이 좋다. 이름에 대한 불평은 그만하고 iterator adapter가 무엇을 하는가?
iterator adapter는 반복자가 순회하면서 할 일을 더해준다. 무슨 말인지는 실제 구현체를 보면 쉽게 이해할 수 있을 것이다. map
함수는 대표적인 adapter다. 함수형 언어를 써본 사람이라면 많이 익숙할 map
함수가 반환하는 반복자는 기존의 값을 새로운 값으로 변환한 값을 순회한다.
이 외에도 표준 라이브러리에 이미 다양한 adapter가 구현돼있다. 이중 가장 많이 사용되는 것은 반복문과 같이 사용하기 좋은 adapter들이다. 조건을 만족하는 값만 돌려주는 filter
, 지정 된 몇 개의 값만 반환하는 take
, 반대로 몇 개의 값은 생략하고 반환하는 skip
, 몇 개씩 값을 건너뛰며 순환하는 step_by
와 같은 adapter가 대표적인 예시다. 이런 adapter를 반복문과 함께 사용하면 복잡한 조건 처리를 쉽게 표현할 수 있다.
이 외에도 영원히 종료하지 않고 순환하게 만드는 cycle
이나, 순환하는 값에는 변환을 주지 않고, 사이드이펙트를 발생시키기만 하는 inspect
도 많이 사용된다.
adapter를 사용할 때 주의해야 할 점이 하나 있다. adapter가 반환하는 것 역시 반복자일 뿐이다. 실제로 반복자를 사용하기 전에는 adapter가 지정한 일을 수행하지 않는다. 쉽게 말해 실제로 값이 필요할 때까지 실행을 미루는 lazy evaluation을 한다는 것이다. 따라서 아래와 같은 코드는 inspect
가 돌려주는 반복자를 사용하지 않았기 때문에 화면에 아무런 값을 출력하지 않는다.
그렇다면 여기서 의문이 하나 들 수 있다. iterator adapter가 뱉는 반복자가 lazy evaluation을 한다면, adapter가 입력으로 사용한 반복자는 어떤 상태가 될까? 실제로 iterator adapter 개념이 존재하는 다른 언어에서 이는 큰 문제가 되기도 한다. 하지만 다행히도 Rust는 ownership을 이용해 문제가 발생하는 것을 사전에 막아준다. iterator adapter는 반복자를 받아 새 반복자를 반환하는 함수다. 다시 말해 반복자의 소유권을 가져간다. 만약 반복자의 레퍼런스를 가져가는 함수였다면, 반복자를 빌려 새 반복자를 만든다고 했을 것이다. 따라서 adapter의 호출자는 adapter의 인자로 넣어 준 반복자를 다시는 사용하지 못한다.
이번 글에서는 iterator adapter가 무엇인지와 함께 자주 사용되는 adapter를 몇 개만 소개해보았다. 실제로는 이보다 더 많은 adapter가 표준 라이브러리에 구현돼 있다. 처음 봤을 때는 이게 어디에 쓰일까 하는 의문이 들 수 있다. 하지만 지금 만들고 있는 프로그램을 잘 살펴보자. 생각보다 반복자가 사용되는 경우는 의외로 많다. 그리고 그중에는 iterator adapter를 사용하면 코드가 더 깔끔해지는 경우가 많다. 게다가 다른 언어였으면 iterator adapter를 사용함으로써 생기는 문제도 Rust에서는 발생하지 않으니 걱정하지 않아도 좋다.
댓글
댓글 쓰기