안녕하세요, 주니어 개발자 Eon입니다.
이번에 다룰 내용은 반복문입니다.
Golang에서의 반복문은 오로지 for
를 사용하는 방법만 존재합니다.
물론 이 for
문을 어떻게 사용하느냐에 따라 다른 언어에 존재하는 반복문 형태를 손쉽게 구현할 수 있습니다.
반복문은 코드의 반복을 위해 존재합니다.
간단한 작업같아도 반복된 작업을 해야 할 때, 우리는 반복문을 사용합니다.
이는 코드의 간결화, 가독성 확보를 위해 꼭 필요합니다.
반복문의 사용은 이중, 삼중으로도 사용이 가능한데 너무 많이 겹쳐두는 것은 좋지 않습니다.
가독성도 좋지 않고, 유지•보수하기 좋지 않습니다.
제 경우엔 삼중을 최대로 두려고 합니다.
그렇다고 겹겹이 쌓인 반복문을 함수로 처리하는 게 좋은가?
그건 또 아닙니다. 콜스택이 쌓이면 퍼포먼스에서 미세하게 차이가 날 수 있으므로 적절한 타협이 필요합니다.
물론 퍼포먼스에 큰 차이는 없지만 극한의 퍼포먼스를 보장해야 하는 상황이라면 직접 테스트하고 사용해야 합니다.
만약, 반복문이 여러 번 반복된다면 해당 역할을 하는 함수를 작성해서 처리하는 방법이 코드의 간소화 및 유지•보수를 위해 좋을 것입니다.
반복문이 있음으로써 할 수 있는 것들은 무궁무진합니다.
가령, 1부터 1000까지의 정수를 출력할 때에도 1000줄을 쓰느냐, 3줄을 쓰느냐는 큰 차이입니다.
위에서 말씀드린 것처럼 Go에서는 for
문만을 제공합니다.
하지만, 이 for
문으로 표현할 수 있는 반복문의 종류는 여러 가지 있습니다.
Effective go에서는 Golang의 반복문을 이와 같이 설명하고 있습니다.
Golang에는 do-while
이 없습니다.
for i := 0; i < 1000; i++ { fmt.Printf("%d ", i) } /* The result of output 0 1 2 3 ... (중략) 999 */
for 선언; 조건; 후처리 작업 {...}
C언어에서 사용하듯이 위와 같이 작성할 수 있습니다.
가장 기본적인 형태이며, 제어하기 가장 쉬운 형태라고 볼 수 있습니다.
i := 0 for i < 1000 { fmt.Printf("%d ", i) } /* The result of output 0 1 2 3 ... (중략) 999 */
for 조건 {...}
C언어에서 사용하는 while
문을 이렇게 표현할 수 있습니다.
위의 for
문은 i < 1000
이라는 조건을 만족하는 중에만 실행됩니다.
{...}
안에 i값을 증가시키거나 다른 특정한 조건을 넣어, i값을 1000보다 큰 값으로 만들어 루프(반복문)를(을) 탈출할 수 있습니다.
(아래에 소개하는 break
를 이용해서 탈출할 수도 있습니다.)
i := 0 for { if i >= 1000 { break } fmt.Printf("%d ", i) i++ } /* The result of output 0 1 2 3 ... (중략) 999 */
C언어에서 사용하는 무한 루프를 이렇게 표현할 수 있습니다.
아무런 조건이 없어, 그저 무한으로 반복되는 루프입니다.
탈출 조건을 명시하지 않으면 컴퓨터의 리소스를 모두 사용할 때까지 무한히 반복됩니다.
위의 코드에서는 i의 값이 1000 이상일 경우, break
를 실행하게 했습니다.
break
문을 실행하면 루프를 탈출하게 됩니다.
var array [4]string array[0] = "Hi" array[1] = "this" array[2] = "is" array[3] = "array" for i, v := range array { fmt.Printf("index : %d \t value : %s \n", i, v) } /* The result of output index : 0 value : Hi index : 1 value : this index : 2 value : is index : 3 value : array */
for 인덱스, 요소 := range 배열 {...}
(array, slice, string, map, channel은 아직 다루지 않은 내용이므로 추후 포스팅할 때 링크 걸어두도록 하겠습니다.)
간단하게 위에 사용된 array
에 대해서만 설명하겠습니다.
array
는 '배열'이며, 값들을 저장합니다.
array
를 string 타입 4개짜리 배열로 선업합니다.for
를 사용해, 배열의 인덱스와 요소들을 모두 순차적으로 출력합니다.
for-range
문은 아래와 같이 사용할 수 있습니다.
for i, v := range array {...}
- 인덱스, 요소 모두를 사용해야 할 때 사용합니다.
for i := range array {...}
- 인덱스만 사용할 때 사용합니다.
for _, v := range array {...}
- 요소만 사용할 때 사용합니다.
for i, v := range "yes, array" { fmt.Printf("index : %d \t value : %c \n", i, v) } /* The result of output index : 0 value : y index : 1 value : e index : 2 value : s index : 3 value : , index : 4 value : index : 5 value : a index : 6 value : r index : 7 value : r index : 8 value : a index : 9 value : y */
for 인덱스, 요소 := range "문자열" {...}
위와 같이 평범한 strings
에 대해서도 사용이 가능합니다.
이 때, v
로 받는 값이 각 문자가 되며, 문자 출력을 위해 %c
를 사용합니다.
a := [4]string{"Hi", "this", "is", "array"} for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 { a[i], a[j] = a[j], a[i] } for i, v := range a { fmt.Printf("index : %d \t value : %s \n", i, v) } /* The result of output index : 0 value : array index : 1 value : is index : 2 value : this index : 3 value : Hi */
for 변수1, 변수2 := 변수1의 값, 변수2의 값; 조건식; 변수1, 변수2 = 변수1에 대한 계산식, 변수2에 대한 계산식 {...}
C언어에서 위와 같이 배열의 순서를 뒤바꾸기 위해서 우리는 'tmp'라는 변수를 만들어 사용하곤 했습니다.
Golang에서는 그럴 필요 없이 '병렬 할당'을 이용하면 됩니다.
병렬 할당
a, b := 1, 100
위의 코드는 좌항 a와 b에, 우항 1과 100을 순차적으로 할당합니다.
var i int = 0 Label1: if i >= 1000 { goto Label2 } fmt.Printf("%d ", i) i++ goto Label1 Label2: fmt.Println("finished") /* The result of output 0 1 2 3 ... (중략) 999 finished */
레이블명:
레이블명은 대소문자 관계없이 지정할 수 있다.
Label
은 위와 같이 사용할 수 있습니다.
레이블은 특정한 조건에 실행해야 하는 코드를 감싸고 있는 플래그라고 보시면 됩니다.
또, 루프의 기능을 하기 위해 만들어진 것은 아니기 때문에 goto
를 사용해 특정 Label
로 이동하는 것을 볼 수 있습니다.
var i int = 0 Label1: for { if i >= 1000 { break Label1 } fmt.Printf("%d ", i) i++ } fmt.Println("finished") /* The result of output 0 1 2 3 ... (중략) 999 finished */
Golang에서는 위와 같이 루프에 Label
을 붙이고 해당 Label
을 break
해서 탈출할 수 있습니다.
반복문을 특정한 조건이 되면 그만두고 싶을 때, 탈출 조건을 명시해야 한다고 했습니다.
탈출 뿐만 아니라, 특정 조건에서의 반복문 점프도 가능합니다.
반복문을 제어하기 위해 사용할 수 있는 것들은 continue
, break
, goto
가 있습니다.
무한 루프가 아니더라도 반복문을 수행하다가 특정 조건에 해당 반복문을 빠져나와야 할 때 사용합니다.
a := 0 for { if a >= 10 { break } a++ } fmt.Println("value of a :", a) /* The result of output value of a : 10 */
위와 같이 무한 루프에서는 break
를 사용해서 '현재'루프를 탈출합니다.
만약 이중 for
문을 사용했고 가장 안 쪽 루프에서 break
를 사용했다면 가장 안 쪽 루프만 탈출하게 됩니다.
반복문을 짜다 보면 특정 조건에서 넘어가게 만들어야 할 때가 있습니다.
그럴 때 continue
는 유용하게 쓰입니다.
b := 0 for { if b < 10 { b++ continue } fmt.Println("value of b :", b) break } /* The result of output value of b : 10 */
b는 0부터 시작해, 1씩 증가합니다.
또, if
조건문 이후에 나오는 결과 출력하는 부분이 있습니다.
하지만, 0부터 9까지는 continue
를 만나게 돼, 출력 파트는 실행되지 않습니다.
반복문 소개하며 보여드린 Label 파트와 중복되는 부분입니다만 goto
를 다시 소개하겠습니다.
c := 0 for { if c >= 10 { goto Label1 } c++ } Label1: fmt.Println("value of c :", c) /* The result of output value of c : 10 */
역시 무한 루프를 돌다가 조건이 만족하면 goto Label1
로 Label1으로 이동하여 루프를 탈출합니다.
이 역시 위에서 한 번 언급이 있었으나, 다시 한 번 소개하겠습니다.
d := 0 Loop1: for { if d >= 10 { break Loop1 } d++ } fmt.Println("value of d :", d) /* The result of output value of d : 10 */
무한 루프에 레이블을 지정했고, 특정 조건에 break Loop1
을 통해 Loop1 레이블에서 탈출할 수 있게 했습니다.
이렇게 루프에 레이블을 지정하면 특정 조건에 다시 해당 레이블로 이동해서 코드를 동작할 수 있다는 장점이 있습니다.
물론 위와 같이 탈출 조건을 명시해서 여러 번 사용할 수도 있습니다.
이번 포스트는 반복문에 대한 내용이었습니다.
감사합니다.👍