본문 바로가기

Languages/Scala

[스칼라] 반복문

반응형

꾸준히 포스트를 작성한다는게 차일피일 미뤄두다 이제 하나씩 정리합니다..^^

매치 표현식을 사용한 흐름제어에 이어 이번 글에서는 반복문에 대해서 다루어 보려고 합니다.

다른 프로그래밍 언어에서도 보편적으로 쓰이는 반복문은 스칼라에서도 비슷한 형태를 가지고 있습니다.

자바 8버전부터 사용 가능한 for-comprehension과 동일한 모양을 가지고 있으며, Range 컬렉션을 사용하여 반복 횟수를, yield 키워드를 사용하여 루프를 결과 컬렉션을 반환하는 표현식으로 전환할 수도 있습니다.

전통적인 while문 역시 지원하나, 스칼라에서는 while문은 결과 컬렉션을 반환하는 표현식으로 사용할 수 없기 때문에 while문보다 for-comprehension의 사용도가 조금 더 높은 것 같습니다.

 

반복문을 설명하기 위해 스칼라의 가장 기본적인 컬렉션인 Immutable List를 여기서 미리 소개하고 이를 활용하여 반복문을 다뤄보도록 하겠습니다. 간단히 소개만 하고, 더 깊은 부분은 추후에 다루도록 하겠습니다.

 

스칼라에서 리스트를 생성하면 기본적으로 Immutable로 선언됩니다. 이는 함수형 프로그래밍 패러다임의 특징 중 하나로, 이는 독립적이고 상태를 가지지 않는 특성을 제공해 주기 위함입니다. 만일 가변 리스트를 val로 선언한다면 해당 값이 '가리키는 객체'는 변경할 수 없겠지만 그 객체 내부의 값들은 얼마든지 수정될 수 있기 때문입니다. 따라서 스칼라에서는 가장 기본적인 컬렉션을 불변 리스트로 지정해두었습니다.

관심 있으신 분들은 다음 공식 문서를 참조해 주세요 : https://docs.scala-lang.org/overviews/collections/overview.html

 

Mutable and Immutable Collections

Scala collections systematically distinguish between mutable and immutable collections. A mutable collection can be updated or extended in place. This means you can change, add, or remove elements of a collection as a side effect. Immutable collections, by

docs.scala-lang.org

리스트를 생성하는 방법은 간단합니다.

val numbers = List(1,2,3,4,5);

다음과 같이 선언해주면 List[Int]가 생성됩니다.

이렇게 생성된 리스트 내의 원소들을 순회하기 위해 for-comprehension을 사용합니다.

for (num <- numbers) {
  println(num)
}

위와 같이 작성하면 원소들이 줄을 바꿔가며 찍혀 나옵니다.

 

하지만 for(int i = 0; i<5; i++) 과 같이 반복 횟수를 지정하고자 한다면 리스트를 만들어 원소를 순회하여 반복 횟수를 정하는 것은 굉장히 비효율적인 동작입니다. 반복 횟수를 지정하여 루프를 돌리기 위해서는 Range 컬렉션을 사용합니다.

Range 컬렉션은 [시작 숫자 to | until 끝 숫자] 의 표현식을 사용하여 생성되며, to는 끝 숫자를 포함하며 until은 끝 숫자를 포함하지 않도록 생성합니다.

for (i <- 1 to 5) {
  print(i)	//12345
}

for (i <- 1 until 5) {
  print(i)	//1234
}

여기서 숫자를 2씩 증가시키는 등의 조건을 걸고 싶다면 반복자 가드 iterator guard를 사용하면 됩니다.

(혹은 Range 컬렉션에 by 조건을 걸 수도 있습니다.)

for (i <- 1 until 10 if i % 2 == 0) {
  print(i)	//2468
}

for (i <- 1 until 10 by 2) {
  print(i)	//13579
}

반복자를 중첩시키는것도 가능합니다.

for (i <- 1 until 5; j <- 1 until 5) {
  print(i*j + " ")
  if(j == 4) println()
}

또한 yield 키워드를 사용하여 루프를 결과 컬렉션을 반환하는 표현식으로 사용할 수도 있습니다.

조금 복잡해 보일 수도 있지만, 각각의 루프를 수행한 결과를 원소로 저장하는 표현식이라고 생각하시면 됩니다.

val doubles = for(i <- 1 until 5) yield {
  i * 2
}

//val doubles: IndexedSeq[Int] = Vector(2, 4, 6, 8)

yield 키워드를 잘 사용하면 소스 코드의 길이를 획기적으로 줄일 수 있습니다.

이렇게 yield 키워드를 사용하여 반환된 결과 컬렉션을 위와 같이 변수/값에 할당하여 사용할 수 있기 때문입니다.

반응형