Meandering Trajectory

Go가 내 에러를 먹었어염! ㅠ.ㅠ 본문

컴퓨터/GoLang

Go가 내 에러를 먹었어염! ㅠ.ㅠ

latentis 2017. 12. 2. 23:57

변수 선언

Go의 기본적인 변수 선언 방법은 다음과 같다.

var v int

Go에서는 변수를 선언할 떄 초기화 하지 않으면 각 타입별 기본값으로 초기화된다. int와 같은 숫자를 표현하는 타입은 0이 기본값이다. 따라서 위와 같이 선언을하고 나면 v의 값은 0이 된다. 원하는 값으로 변수를 초기화하고 싶다면 이렇게 하면 된다.

var v int = 7

또는

var v = int(7)

이렇게 해도 된다.

단축형 선언

그리고 Go에는 변수를 선언하는 다른 방법이 하나 있으니 바로 단축형 변수 선언이다. 다음과 같이 ":="를 이용해서 단축형 선언을 할 수 있다.

v := 7

타이핑을 적게 한다는 것은 반길 일이다. 단축형 선언에는 독특한 특성이 하나 있는데 바로 변수 재선언이 가능하다는 것이다. 아래 코드는 문법적으로 문제가 없다.

x := 1
x, y := 11, 12

두번째 문장에서 x가 다시 선언되는 것처럼 보이지만 실제로 선언된 것은 y 뿐이고 x는 값만 바뀐 것이다. 두번째 문장이 정상적으로 컴파일되는 이유는 새로 선언되는 y가 있기 때문이다. 다음과 같은 재선언은 허용되지 않는다.

x := 1
x := 11

이 코드를 컴파일하려 하면 다음과 같은 에러메시지와 함께 컴파일이 실패하게 된다.

no new variables on left side of :=

즉 문장 내에 새로 선언되는 변수가 최소한 하나는 있어야 ":="를 이용해 기존 값 변경이 가능하다.

믈론 괄호를 이용해 새로운 코드 블록을 만든 경우에는 같은 이름으로 변수 선언이 가능하다.

x := 1
{
    x := 11
}

이 경우 첫번째와 두번째 x는 서로 다른 메모리 공간에 할당된다. 그리고 두번쨰 선언문이 속한 코드 블록 내에서는 새로 선언된 x가 바깥쪽에 선언된 x를 가리게 된다. 즉 x라는 이름으로 바깥 쪽의 변수 x에 접근할 수 없다.

Go가 에러코드를 먹었어염! ㅠ.ㅠ

":="은 편리하다. 2글자만 입력하면 되니 var과 type을 조합한 기본형보다 훨씬 많이 쓰게 된다. 그리고 함수의 반환값을 이용한 다음과 같은 선언도 가능하기 때문에 그 편리함은 배가된다.

x := fn()

그러나 편리하니 자주 쓰게 되고 자주 쓰다보면 써서는 안 되는 곳에 쓰게 되는 사고가 꼭 터진다. 아래 코드를 보자.

func doAorB(useA bool) error {
    // error 변수 선언, nil로 초기화 됨.
    var err error

    if useA {
        // =를 써야 할 자리에 :=를 쓰고 있음.
        err := A()
    } else {
        // =를 써야 할 자리에 :=를 쓰고 있음.
        err := B()
    }

    // err는 항상 nil
    return err
}

이 함수의 원래 의도는 파라미터 useA의 값에 따라 A혹은 B를 호출한 뒤 반환된 에러를 err에 저장하고 이 값을 반환하는 것이다. 하지만 위 함수 doAorB는 항상 error로 nil을 반환하게 된다.

if 블럭과 else 블럭 안에서 "="를 써야 할 자리에 ":="를 사용했기 때문이다. ":="를 사용했기 때문에 함수 A나 B가 반환한 에러가 해당 코드 블럭 내에서만 보이는 새로운 변수 err에 저장되고 처음해 선언한 err 변수는 변경되지 않아 초기값 nil로 남게 된다. 결국 doAorB를 호출한 코드는 항상 에러로 nil 값을 건네받기 때문에 실제로 에러가 난 상황이어도 에러를 처리하지 않고 그냥 지나치게 된다.

때때로 이렇게 편리함은 실수로 이어질 가능성을 높인다. ":="는 분명 편리한 기능이지만 편리한 만큼 큰 문제를 야기할 수 있으니 사용할 때 항상 제대로 된 곳에 사용하고 있는지 확인이 필요하다. 그리고 본인이 에러를 먹게 코드를 짜고 Go 탓을 하지는 말자. ^^

'컴퓨터 > GoLang' 카테고리의 다른 글

if 문의 조건절  (0) 2018.04.08
인터페이스 타입과 nil  (0) 2018.02.10
Go 코드에서의 에러 처리  (0) 2017.11.18
new와 make  (0) 2017.11.12
select 문: 여러 채널에서 데이터 읽어 처리하기  (0) 2017.11.10
Comments