프로그래밍 언어 & 프레임워크/Golang

Go: Switch 를 사용하여 타입 체크하기 (Reflection) [Effective Go]

Switch

일반적으로 다른 언어에서는 어떤 값의 타입에 따라 다른 행동을 하고 싶을 때 Reflection 를 사용하여 해결한다. Go 에서는 특이하게도 언어차원에서 Switch 를 사용하여 해결할 수 있는데, 다음과 같이 해볼 수 있다.

var t interface{} = map[string]string{
	"sayHello": "Hello, Go!",
}

switch t := t.(type) {
case string:
	fmt.Println(t)
case map[string]string:
	for k, v := range t {
		fmt.Println(k, v)
	}
}

Switch 와 함께 타입 단언(Type Assertion)을 사용하여 해결할 수 있다. 그런데 자세히 살펴보면 map 타입에 대해서는 상당히 불편한 사항을 발견할 수 있는데, 키와 값의 타입이 반드시 지정이 되어 있어야 체크가 가능하다는 점이 바로 그것이다.

reflect 패키지로 타입 체크하기

키와 값에 구분없이 단순히 포인터인 경우, 맵인 경우와 같이 종류만으로만 점검하고 싶다면 reflect 패키지를 사용하면 해결할 수 있다. reflect 패키지를 사용하여 타입을 체크하면 다음과 같이 바꿀 수 있다. 이렇게 바꾸면 맵 타입에 대해 키와 값 타입에 상관없이 체크가 가능하다.

t := map[string]string{
	"sayHello": "Hello, Go!",
}

switch rv := reflect.ValueOf(t); rv.Kind() {
case reflect.String:
	fmt.Println(rv.String())
case reflect.Map:
	for k, v := range t {
		fmt.Println(k, v)
	}
}

reflect.ValueOf() 함수는 reflect.Value 를 반환하는데, 이 타입의 메서드들은 우리가 값으로 넘긴 것에 대한 값 자체에 대한 정보가 담겨있다. 여기서 Value.Kind() 메서드를 쓰면 해당 값의 종류를 알 수 있다. 리턴하는 값은 reflect.Kind 타입을 가진다. KindType 과는 다른데, Value.Type().String() 으로 하게 되면 map[string]string 이 나올 것이고, Value.Kind().String() 를 사용하게 되면 map 이 나온다.