더북(TheBook)

다음 코드는 임의의 값 x를 매개변수로 받아 x의 길이를 반환하는 함수이다.

func Len(x interface{}) int {
    value := reflect.ValueOf(x)
    switch reflect.TypeOf(x).Kind() {
    case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
        return value.Len()
    default:
        if method := value.MethodByName("Len"); method.IsValid() {
            values := method.Call(nil)
            return int(values[0].Int())
        }
    }
     
    panic(fmt.Sprintf("'%v' does not have a length", x))
 
}

xlen() 함수를 지원하는 내장 타입이라면 reflect.Value.Len() 메서드를 사용하여 길이를 바로 반환한다. 그 외에는 Len() 메서드가 있는지 확인해서(reflect.Value.MethodByName("Len")) Len 메서드를 동적으로 호출한 후(reflect.Value.Call()) 결과를 반환한다. Len() 함수가 없다면 패닉을 발생시키고 프로그램을 종료한다.

다음 main 함수에서는 앞에서 정의한 Len() 함수로 값의 길이를 구한다.


func main() {
    a := list.New()                       // a.Len() == 0
    b := list.New()
    b.PushFront(0.5)                      // b.Len() == 1
    c := map[string]int{"A": 1, "B": 2}   // len(c) == 2
    d := "one"                            // len(d) == 3
    e := []int{5, 0, 4, 1}                // len(e) == 4
     
    fmt.Println(Len(a), Len(b), Len(c), Len(d), Len(e))
}

실행 결과

0 1 2 3 4

a, b, c, d, e는 저마다 다른 타입이지만, 모두 Len() 함수로 길이를 구했다.

Go의 reflect 패키지는 굉장히 유연하고 런타임 시 동적인 작업을 할 수 있게 해준다. 하지만 그만큼 사용할 때 주의를 기울여야 한다. Go 언어를 설계하고 개발하는데 초기부터 참여했던 롭 파이크(Rob Pike)는 ‘리플렉션은 강력한 도구이지만, 조심히 사용해야 하고 꼭 필요하지 않다면 사용하지 않는 것이 좋다’고 강조했다.

신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.