반복문

반복문 (Loops)

코드의 흐름을 반복으로 제어하고 싶을 때, loop와 이를 돕는 문장들을 어떻게 쓰는지 살펴볼게요. 다룰 내용은 for 루프, whiledo while 루프, 그리고 breakcontinue예요.

출처: Dart 공식 문서

본문

이 페이지는 루프와 이를 지원하는 문장을 사용해 Dart 코드의 흐름을 제어하는 방법을 보여줘요.

  • for 루프
  • whiledo while 루프
  • breakcontinue

Dart에서 제어 흐름을 다루는 다른 방법도 있어요.

For 루프

표준 for 루프로 반복할 수 있어요. 예를 들면 다음과 같아요.

var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
  message.write('!');
}

Dart의 for 루프 안에 있는 클로저는 인덱스의 (value)을 캡처해요. 이 덕분에 JavaScript에서 흔히 겪는 함정을 피할 수 있어요. 다음 예시를 볼게요.

var callbacks = [];
for (var i = 0; i < 2; i++) {
  callbacks.add(() => print(i));
}

for (final c in callbacks) {
  c();
}

출력은 예상대로 0 다음에 1이에요. 반면 같은 예시를 JavaScript로 쓰면 22가 출력돼요.

ListSet 같은 Iterable 타입을 반복할 때는 현재 반복 횟수를 알 필요가 없을 때가 많아요. 그럴 때는 for-in 루프를 쓰는 게 코드가 더 깔끔해요.

for (var candidate in candidates) {
  candidate.interview();
}

위 예시 루프에서 candidate는 루프 본문 안에서 정의되고, candidates의 값을 한 번에 하나씩 참조하도록 설정돼요. candidate는 로컬 변수라서, 루프 본문 안에서 candidate를 다시 할당해도 그 반복 동안의 로컬 변수만 바뀌고 원래 candidates iterable은 수정되지 않아요.

iterable에서 얻은 값을 처리할 때는 for-in 루프에 패턴을 쓸 수도 있어요.

for (final Candidate(:name, :yearsExperience) in candidates) {
  print('$name has $yearsExperience of experience.');
}

Iterable 클래스는 다른 선택지로 forEach() 메서드도 제공해요.

var collection = [1, 2, 3];
collection.forEach(print); // 1 2 3

While과 do-while

while 루프는 루프 본문을 실행하기 전에 조건을 평가해요.

while (!isDone()) {
  doSomething();
}

반면 do-while 루프는 루프 본문을 실행한 후에 조건을 평가해요.

do {
  printLine();
} while (!atEndOfPage());

Break와 Continue

break는 반복을 멈출 때 써요.

while (true) {
  if (shutDownRequested()) break;
  processIncomingRequests();
}

continue는 다음 반복으로 건너뛸 때 써요.

for (int i = 0; i < candidates.length; i++) {
  var candidate = candidates[i];
  if (candidate.yearsExperience < 5) {
    continue;
  }
  candidate.interview();
}

리스트나 집합 같은 Iterable을 쓴다면, 위 예시를 다르게 쓸 수도 있어요.

candidates
    .where((c) => c.yearsExperience >= 5)
    .forEach((c) => c.interview());

라벨 (Labels)

라벨(label)은 콜론이 붙은 식별자(labelName:)로, 문장 앞에 놓아 labeled statement(라벨이 붙은 문장)를 만들 수 있어요. 루프와 switch case가 라벨이 붙은 문장으로 자주 쓰여요. 라벨이 붙은 문장은 나중에 breakcontinue 문장에서 이렇게 참조할 수 있어요.

  • break labelName; — 라벨이 붙은 문장의 실행을 종료해요. 중첩된 루프 안에 있을 때 특정 바깥쪽 루프에서 빠져나오려는 경우에 유용해요.
  • continue labelName; — 라벨이 붙은 문장 루프의 현재 반복 중 나머지를 건너뛰고 다음 반복을 계속해요.

라벨은 제어 흐름을 관리하는 데 쓰여요. 보통 루프와 switch case와 함께 쓰이며, 기본적으로 가장 안쪽 루프에 영향을 주는 대신 어느 문장에서 빠져나오거나 계속할지 지정해 줘요.

for 루프에서 break로 라벨 쓰기

outerLoop라는 라벨을 break 문장과 함께 for 루프에서 사용하는 코드를 볼게요.

outerLoop:
for (var i = 1; i <= 3; i++) {
  for (var j = 1; j <= 3; j++) {
    print('i = $i, j = $j');
    if (i == 2 && j == 2) {
      break outerLoop;
    }
  }
}
print('outerLoop exited');

위 예시에서 i == 2이고 j == 2일 때, break outerLoop; 문장이 안쪽과 바깥쪽 루프를 모두 멈춰요. 그 결과 출력은 다음과 같아요.

i = 1, j = 1
i = 1, j = 2
i = 1, j = 3
i = 2, j = 1
i = 2, j = 2
outerLoop exited

for 루프에서 continue로 라벨 쓰기

outerLoop라는 라벨을 continue 문장과 함께 for 루프에서 사용하는 코드를 볼게요.

outerLoop:
for (var i = 1; i <= 3; i++) {
  for (var j = 1; j <= 3; j++) {
    if (i == 2 && j == 2) {
      continue outerLoop;
    }
    print('i = $i, j = $j');
  }
}

위 예시에서 i == 2이고 j == 2일 때, continue outerLoop;i = 2의 나머지 반복을 건너뛰고 i = 3으로 이동해요. 그 결과 출력은 다음과 같아요.

i = 1, j = 1
i = 1, j = 2
i = 1, j = 3
i = 2, j = 1
i = 3, j = 1
i = 3, j = 2
i = 3, j = 3

while 루프에서 break로 라벨 쓰기

outerLoop라는 라벨을 break 문장과 함께 while 루프에서 사용하는 코드를 볼게요.

var i = 1;

outerLoop:
while (i <= 3) {
  var j = 1;
  while (j <= 3) {
    print('i = $i, j = $j');
    if (i == 2 && j == 2) {
      break outerLoop;
    }
    j++;
  }
  i++;
}
print('outerLoop exited');

위 예시에서 i == 2이고 j == 2일 때 프로그램은 안쪽과 바깥쪽 while 루프를 모두 빠져나와요. 그 결과 출력은 다음과 같아요.

i = 1, j = 1
i = 1, j = 2
i = 1, j = 3
i = 2, j = 1
i = 2, j = 2
outerLoop exited

while 루프에서 continue로 라벨 쓰기

outerLoop라는 라벨을 continue 문장과 함께 while 루프에서 사용하는 코드를 볼게요.

var i = 1;

outerLoop:
while (i <= 3) {
  var j = 1;
  while (j <= 3) {
    if (i == 2 && j == 2) {
      i++;
      continue outerLoop;
    }
    print('i = $i, j = $j');
    j++;
  }
  i++;
}

위 예시에서 i = 2이고 j = 2일 때의 반복은 건너뛰고 루프가 직접 i = 3으로 이동해요. 그 결과 출력은 다음과 같아요.

i = 1, j = 1
i = 1, j = 2
i = 1, j = 3
i = 2, j = 1
i = 3, j = 1
i = 3, j = 2
i = 3, j = 3

do-while 루프에서 break로 라벨 쓰기

outerLoop라는 라벨을 break 문장과 함께 do while 루프에서 사용하는 코드를 볼게요.

var i = 1;

outerLoop:
do {
  var j = 1;
  do {
    print('i = $i, j = $j');
    if (i == 2 && j == 2) {
      break outerLoop;
    }
    j++;
  } while (j <= 3);
  i++;
} while (i <= 3);

print('outerLoop exited');

위 예시에서 i == 2이고 j == 2일 때 프로그램은 안쪽과 바깥쪽 루프를 모두 빠져나와요. 그 결과 출력은 다음과 같아요.

i = 1, j = 1
i = 1, j = 2
i = 1, j = 3
i = 2, j = 1
i = 2, j = 2
outerLoop exited

do-while 루프에서 continue로 라벨 쓰기

outerLoop라는 라벨을 continue 문장과 함께 do while 루프에서 사용하는 코드를 볼게요.

var i = 1;

outerLoop:
do {
  var j = 1;
  do {
    if (i == 2 && j == 2) {
      i++;
      continue outerLoop;
    }
    print('i = $i, j = $j');
    j++;
  } while (j <= 3);
  i++;
} while (i <= 3);

위 예시에서 루프는 i = 2이고 j = 2일 때를 건너뛰고 직접 i = 3으로 이동해요. 그 결과 출력은 다음과 같아요.

i = 1, j = 1
i = 1, j = 2
i = 1, j = 3
i = 2, j = 1
i = 3, j = 1
i = 3, j = 2
i = 3, j = 3

더 알아보기 (Learn more)