7.3.6 리플렉션
reflect 패키지를 사용하면 프로그램의 메타 데이터를 활용하여 객체를 동적으로 제어할 수 있다. 즉, 런타임 시 타입이 정해지지 않은 값의 실제 타입을 확인하여 그 값의 메서드를 호출하거나 내부 필드에 접근할 수 있다. reflect 패키지의 주요 기능을 살펴보자.
타입/값 정보 확인
Go의 모든 값은 요소 두 개로 구성된다. 하나는 값의 타입이고 또 하나는 실제 값이다. 타입은 reflect.TypeOf() 함수로 확인하고, 실제 값은 reflect.ValueOf() 함수로 확인한다.
x := 1 y := 1.1 z := "one" fmt.Printf("x: %v(%v)\n", reflect.ValueOf(x).Int(), reflect.TypeOf(x)) fmt.Printf("y: %v(%v)\n", reflect.ValueOf(y).Float(), reflect.TypeOf(y)) fmt.Printf("z: %v(%v)\n", reflect.ValueOf(z).String(), reflect.TypeOf(z))
실행 결과
x: 1(int)
y: 1.1(float64)
z: one(string)
reflect.ValueOf() 함수는 실제 값의 정보를 담고 있는 reflect.Value 타입 값을 반환한다. reflect.Value 타입에는 reflect.Value.Bool(), reflect.Value.Complex(), reflect.Value.Float(), reflect.Value.Int(), reflect.Value.String()처럼 실제 값을 확인하는 메서드가 있다.
슬라이스와 맵 같은 컬렉션 타입이나 구조체도 리플렉션으로 메타 정보를 확인할 수 있다. 구조체의 태그 정보에 접근할 때도 리플렉션을 사용한다.
type User struct { Name string "check:len(3,40)" Id int "check:range(1,999999)" } u := User{"Jang", 1} uType := reflect.TypeOf(u) if fName, ok := uType.FieldByName("Name"); ok { fmt.Println(fName.Type, fName.Name, fName.Tag) } if fId, ok := uType.FieldByName("Id"); ok { fmt.Println(fId.Type, fId.Name, fId.Tag) }
실행 결과
string Name check:len(3,40)
int Id check:range(1,999999)
struct의 태그는 필드의 정합성 규칙이나 JSON/XML 변환을 위한 정보를 표현하는 용도로 자주 사용된다.