Rust의 반복문
Java나 C++ 같은 언어에서는 조건 반복문과 for-each 반복문에 같은 for
키워드를 사용한다. 하지만, Rust는 조건 반복문에는 while 키워드
을 for-each 반복문에는 for
키워드를 사용한다.
Rust는 여기에 하나의 반복문을 더 제공한다. loop
반복문이다. 이는 while true
라고 쓰는 것과 같이 같은 코드를 무한히 실행한다. 실제로 무한 반복이 필요한 경우에도 사용되고, 반복문의 조건을 하나의 표현식으로 서술하기 힘들어 break
문으로 뺄 때에도 사용된다.
하지만 loop
가 while true와 완전히 같은 코드는 아니다. loop
는 while
문과 다르게 그 자체로 값을 가진다. break
문 뒤에 값을 적으면 이 값이 반복문 전체의 값이 된다. 그렇다면 다른 반복문은 값을 가지지 않는데 loop
문만 값을 가지는 이유는 무엇일까?
일반적으로 반복문이 끝나는 데는 두 가지 조건이 있다. 주어진 조건이 끝나는 것과 break
문을 만나는 것이다. 평범한 반복문에서도 같은 문법을 써서 break
문을 만났을 때의 값은 정하게 할 수는 있지만, 조건이 끝나 반복문이 종료되는 경우 값을 지정할 수 없다. 그래서 일반적으로 반복문은 값을 가지지 않는다. 하지만 loop
문은 종료 조건이 없기 때문에 끝나기 위해서는 항상 break
문을 만나야 한다. 이런 특징 덕분에 loop
는 다른 반복문과 다르게 구문 자체가 값을 가질 수 있다.
Rust에서는 for-each 반복문을 for-in 반복문이라고 부른다. 실제로 for value in values
라고 코드를 작성하기 때문이다. 그렇다면 여기서 values
에 들어갈 수 있는 값은 어떤 값일까? 내가 만든 타입을 for-in 반복문에 사용하고 싶으면 어떻게 해야 할까?
값을 순회할 수 있는 타입은 모두 for-in 반복문에 사용할 수 있다. Rust에서는 Iterator
가 순회할 수 있는 타입을 의미한다. 다시 말해 for-in 반복문은 Iterator
를 사용한다.
하지만 for-in 반복문을 사용하려면 Iterator
를 구현해야 한다는 표현은 정확하지 않다. Rust가 생각하는 순회할 수 있는 타입은 Iterator
로 변환할 수 있는 타입이다. 구체적으로는 IntoIterator
를 구현한 타입은 for-in 반복문에 사용할 수 있다. Iterator
를 구현한 타입은 자동으로 IntoIterator
도 구현하기 때문에 Iterator
를 구현한 타입도 for-in 반복문에 사용할 수 있다. 하지만 Iterator
를 구현하지 않아도, IntoIterator
를 구현한 타입은 for-in 반복문에 사용할 수 있다.
새로 정의한 타입을 for-in 반복문에서 사용하게 만들 때 기억해야 할 것이 있다. IntoIterator
를 구현할 때 원하는 타입뿐 아니라 그 타입의 레퍼런스와 mutable 레퍼런스도 IntoIterator
를 구현해야 한다. 예를 들어 List
라는 타입을 만들었을 때, List뿐 아니라 &List
와 &mut List
에도 IntoIterator
를 구현해야 한다.
이는 for-in 반복문을 3가지 형태로 사용할 수 있기 때문이다. 예를 들어 list
라는 자료구조를 순회할 때 for x in list
라고 써서 list
자체를 move하여 순회할 수도 있지만, for x in &list
라는 식으로 list
의 원소의 레퍼런스에 대해 순회할 수도 있고, for x in &mut list
라는 식으로 사용하여 반복문 안에서 list
의 원소를 수정하게 할 수도 있다. 따라서 IntoIterator
를 레퍼런스와 mutable 레퍼런스에도 의미에 맞게 구현해야 한다.
여기서 "의미에 맞게"라는 것은 IntoIterator
의 Item
타입이 적절한 타입을 가지는 것을 말한다. 사람들은 for x in &list
라는 코드를 쓸 때 x
로 list
의 원소를 별도의 복사 없이 레퍼런스로 접근할 수 있다고 예상한다. 따라서 &List
의 IntoIterator
의 Item
은 레퍼런스 타입이어야 한다. 비슷하게 for x in &mut list
라는 코드를 쓸 때는 x
를 수정하여 list
의 원소를 수정할 수 있을 것으로 생각하기 때문에 &mut List
의 IntoIterator
는 list
의 원소를 가리키는 mutable 레퍼런스여야 한다.
앞에서 말했듯이 Iterator
도 IntoIterator
를 구현한다. 따라서 iterator adapter가 돌려주는 다양한 Iterator
들도 for-in 반복문에 사용할 수 있다. 이에 대해서는 다음 기회에 iterator adapter를 소개하면서 더 자세히 다뤄보도록 하겠다.
loop가 값을 가질 수 있는 건 정말 좋은 피쳐인듯..
답글삭제살면서 Rust를 쓸 일이 있을까 싶긴한데 여튼 좋은 정보인듯합니다.
안녕하세요?
답글삭제저는 인공지능 스타트업에 다니는 정승환이라고 합니다.
블로그의 내용들 정말 잘 보았습니다. 소중한 지식의 나눔, 감사드립니다.
관련해서 간단하게 제안드릴 내용(온라인 강의)이 있어서
메일로 연락드리고 싶습니다.
정말 바쁘시겠지만,
메일 한 번 이야기 나누어 볼 수 있을까요?
제 메일은
hwan@lionrocket.ai
입니다. 회신주시면, 제안내용과 함께 꼭 설명드리고 싶습니다.
좋은 하루 되세요 :)
정승환 드림