[루비 사용자 가이드] 컨트롤 구조들

루비/레일스 프로그래밍/루비 사용자 가이드 2007.04.29 17:58

이번 장은 루비의 컨트롤 구조를 더 자세히 살펴봅니다.

case

case는 순차적으로 여러 조건을 검사할 때 사용합니다. 이것은 겉보기에는 자바나 C의 switch와 비슷해 보입니다. 그러나, 나중에 살펴보게 되면 알게 되겠지만, 그보다 훨씬 더 강력합니다.

ruby> i=8
ruby> case i
    | when 1, 2..5
    |   puts "1..5"
    | when 6..10
    |   puts "6..10"
    | end
6..10
   nil

2..5는 2부터 5까지의 범위(range)를 나타내는 식입니다(2와 5를 모두 포함). 다음 식은 i의 값이 이 범위 안에 속하는지 검사합니다:

(2..5) === i

case는 여러 조건을 검사하기 위해 내부적으로 관계 연산자 ===를 사용합니다. 루비의 객체 지향적 특성에 따라 ===when 조건에 있는 객체의 특성에 맞게 해석됩니다. 예를 들어 다음 코드는 첫 번째 when에서는 스트링의 동등성 테스트를 진행하고 두번째의 when에서는 정규식의 패턴 매치를 수행합니다.

ruby> case 'abcdef'
    | when 'aaa', 'bbb'
    |   puts "aaa or bbb"
    | when /def/
    |   puts "includes /def/"
    | end
includes /def/
   nil

while

다음 번 글에서 이터레이터(iterators)를 사용하는 방법을 알게 되면, 명시적으로 루프를 작성할 필요는 거의 없어지겠지만, 루프를 만드는 편리한 방법도 있습니다.

while
if를 여러 번 반복하는 것과 같습니다. 우리는 이 명령을 이미 단어 추측 퍼즐과 정규식 프로그램에서 사용했습니다(예전의 글을 참조하세요). 거기서 while condition ... end으로 코드 조각을 둘러싸서, condition이 참인 동안 코드를 반복 수행 했습니다. 그렇지만 whileif는 한 문장에도 쉽게 적용할 수 있습니다:

ruby> i = 0
   0
ruby> puts "It's zero." if i==0
It's zero.
   nil
ruby> puts "It's negative." if i<0
   nil
ruby> puts i+=1 while i<3
1
2
3
   nil

때때로 테스트 할 조건의 역을 취할 필요가 있습니다. unlessif를 뒤집은 것이고, untilwhile를 뒤집은 것입니다. 이 명령어를 가지고 실험해 보는 것은 독자들의 몫으로 남겨놓겠습니다.

루프 내부에서 루프의 진행을 바꾸는 방법이 네가지 있습니다. 첫째로, break는 C에서와 마찬가지로 루프에서 완전히 벗어날 때 사용합니다. 두번째로, next는 루프의 컨트롤을 다음 번 반복(iteration)의 시작부분으로 넘깁니다(C의 continue와 같습니다). 세번째로, redo가 있습니다. redo는 현재의 반복을 다시 시작합니다. 다음 C코드는 break, next, redo의 의미를 goto로 보여주는 것입니다:

while (condition) {
label_redo:
   goto label_next;        /* ruby's "next" */
   goto label_break;       /* ruby's "break" */
   goto label_redo;        /* ruby's "redo" */
   ...
   ...
label_next:
}
label_break:
...

루프 내부에서 밖으로 나가는 네 번째 방법은 return입니다. return을 계산하게 되면 루프에서 뿐 아니라 그 루프를 포함하고 있는 메소드에서도 빠져나가게 됩니다. 만약 return에 인자가 주어지면, 그 값이 메소드 호출의 반환값으로 전달되며, 인자가 없으면 nil이 반환됩니다.

for

C 프로그래머라면 "for" 루프를 어떻게 만들 수 있을지 궁금할 것입니다. 루비에서는 for가 동일한 목적으로 제공되지만, 더 유연합니다. 다음 코드의 루프는 한 컬렉션(collection) (배열, 해시, 숫자 시퀀스, 등.)의 각 원소를 한번씩 방문합니다. 하지만 프로그래머가 컬렉션의 원소를 참조하기 위한 인덱스에 대해 고민할 필요는 없습니다:

for elt in collection
  # ... 여기서, elt는 컬렉션의 한 원소를 가리킴
end

컬렉션은 또한 값의 범위일 수도 있습니다(for 루프라 할 때는 대부분 이 경우입니다):

ruby> for num in (4..6)
    |    puts num
    | end
4
5
6
   4..6

다음 예에서는 배열의 원소를 차례로 처리합니다:

ruby> for elt in [100,-9.6,"pickle"]
    |    puts "#{elt}\t(#{elt.class})"
    | end
100    (Fixnum)
-9.6   (Float)
pickle (String)
   [100, -9.6, "pickle"]

하지만, 더 알아야 할 내용이 있습니다. for는 실제로는 each를 쓰는 다른 방법입니다. 따라서, each는 우리가 처음 다루게 되는 이터레이터의 예가 됩니다. 다음 두 코드는 동일합니다:

#  만약 C나 자바에 익숙하다면 이쪽이 더 좋게 느껴질겁니다.
for element in collection
  ...
end

#  스몰토크(Smalltalk) 프로그래머는 이것을 더 좋아할겁니다.
collection.each {|element|
  ...
}

이터레이터는 전통적인 루프를 대부분 대치할 수 있습니다. 그리고, 일단 한 번 익숙해지면 전통적인 루프보다 더 사용하기 쉽습니다. 따라서, 이제 이터레이터에 대해 더 자세히 배우도록 합시다.


Trackbacks 0 : Comments 0

Write a comment