Rust의 반복문

Java나 C++ 같은 언어에서는 조건 반복문for-each 반복문에 같은 for 키워드를 사용한다. 하지만, Rust는 조건 반복문에는 while 키워드을 for-each 반복문에는 for 키워드를 사용한다.

Rust는 여기에 하나의 반복문을 더 제공한다. loop 반복문이다. 이는 while true라고 쓰는 것과 같이 같은 코드를 무한히 실행한다. 실제로 무한 반복이 필요한 경우에도 사용되고, 반복문의 조건을 하나의 표현식으로 서술하기 힘들어 break문으로 뺄 때에도 사용된다.

하지만 loopwhile true와 완전히 같은 코드는 아니다. loopwhile문과 다르게 그 자체로 값을 가진다. break문 뒤에 값을 적으면 이 값이 반복문 전체의 값이 된다. 그렇다면 다른 반복문은 값을 가지지 않는데 loop문만 값을 가지는 이유는 무엇일까?

일반적으로 반복문이 끝나는 데는 두 가지 조건이 있다. 주어진 조건이 끝나는 것과 break문을 만나는 것이다. 평범한 반복문에서도 같은 문법을 써서 break문을 만났을 때의 값은 정하게 할 수는 있지만, 조건이 끝나 반복문이 종료되는 경우 값을 지정할 수 없다. 그래서 일반적으로 반복문은 값을 가지지 않는다. 하지만 loop문은 종료 조건이 없기 때문에 끝나기 위해서는 항상 break문을 만나야 한다. 이런 특징 덕분에 loop는 다른 반복문과 다르게 구문 자체가 값을 가질 수 있다.

Rust에서는 for-each 반복문을 for-in 반복문이라고 부른다. 실제로 for value in values라고 코드를 작성하기 때문이다. 그렇다면 여기서 values에 들어갈 수 있는 값은 어떤 값일까? 내가 만든 타입을 for-in 반복문에 사용하고 싶으면 어떻게 해야 할까?

값을 순회할 수 있는 타입은 모두 for-in 반복문에 사용할 수 있다. 따라서 무엇을 for-in 반복문에 사용할 수 있는지 알고 싶다면 Rust가 생각하는 순회할 수 있는 값이 무엇인지 알아야 한다.

Iterator는 순회할 수 있는 타입을 의미한다. 따라서 Iterator를 구현한 타입도 for-in 반복문에 사용할 수 있다. 하지만 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 레퍼런스에도 의미에 맞게 구현해야 한다.

여기서 "의미에 맞게"라는 것은 IntoIteratorItem 타입이 적절한 타입을 가지는 것을 말한다. 사람들은 for x in &list라는 코드를 쓸 때 xlist의 원소를 별도의 복사 없이 레퍼런스로 접근할 수 있다고 예상한다. 따라서 &ListIntoIteratorItem은 레퍼런스 타입이어야 한다. 비슷하게 for x in &mut list라는 코드를 쓸 때는 x를 수정하여 list의 원소를 수정할 수 있을 것으로 생각하기 때문에 &mut ListIntoIteratorlist의 원소를 가리키는 mutable 레퍼런스여야 한다.

앞에서 말했듯이 IteratorIntoIterator를 구현한다. 따라서 iterator adapter라고 불리는 다양한 Iterator들도 for-in 반복문에 사용할 수 있다. 이에 대해서는 다음 기회에 iterator adapter를 소개하면서 더 자세히 다뤄보도록 하겠다.

댓글

  1. loop가 값을 가질 수 있는 건 정말 좋은 피쳐인듯..
    살면서 Rust를 쓸 일이 있을까 싶긴한데 여튼 좋은 정보인듯합니다.

    답글삭제
  2. 안녕하세요?
    저는 인공지능 스타트업에 다니는 정승환이라고 합니다.
    블로그의 내용들 정말 잘 보았습니다. 소중한 지식의 나눔, 감사드립니다.

    관련해서 간단하게 제안드릴 내용(온라인 강의)이 있어서
    메일로 연락드리고 싶습니다.
    정말 바쁘시겠지만,
    메일 한 번 이야기 나누어 볼 수 있을까요?

    제 메일은
    hwan@lionrocket.ai
    입니다. 회신주시면, 제안내용과 함께 꼭 설명드리고 싶습니다.

    좋은 하루 되세요 :)
    정승환 드림

    답글삭제

댓글 쓰기

이 블로그의 인기 게시물

[C++] enum class - 안전하고 쓰기 쉬운 enum

Chromium OS 설치 후기

[MongoDB] ObjectId에 대해서