reflect 사용 이유
reflect는 여러 가지의 사용방법이 있겠지만 저는 종종 협업을 하면서 상대방이 보낸 데이터의 타입 및 종류에 대하여 구분이 필요한 경우 사용하였습니다.
reflect를 이용하여 타입 가져오기
인터페이스 형식으로 데이터를 받아 받은 데이터의 타입을 구분할 수 있습니다.
package main
import (
"fmt"
"reflect"
)
func ShowType(i interface{}) {
fmt.Println(reflect.ValueOf(i).Type())
}
func main() {
num := 100
ShowType(num)
job := "student"
ShowType(job)
}
/* 출력결과
int
string
*/
코드설명
reflect.ValueOf().Type()을 사용하여 해당 타입이 어떤 타입인지 알 수 있습니다.
reflect를 이용하여 구조체 멤버 변수 확인하기
reflect를 사용하여 인터페이스로 받은 구조체의 멤버 변수들을 확인하도록 하겠습니다. 여기서 중요한 건 멤버 변수가 없는 일반 변수의 인터페이스를 넘기면 panic이 발생합니다.
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Job string `json:"job"`
}
func (p Person) Print() {
fmt.Println(p.Name, " is ", p.Job)
}
func ShowMetaData(i interface{}) {
elements := reflect.ValueOf(i).Elem()
for index := 0; index < elements.NumField(); index++ {
typeField := elements.Type().Field(index)
fmt.Println(typeField.Name, typeField.Type, typeField.Tag, elements.Field(index))
}
}
func main() {
p := &Person{
Name: "Han",
Age: 30,
Job: "Developer",
}
ShowMetaData(p)
// panic 발생
//num := 100
//ShowMetaData(num)
}
/* 출력결과
Name string json:"name" Han
Age int json:"age" 30
Job string json:"job" Developer
*/
코드설명
ShowMetaData() 함수를 보면 interface의 value를 reflect.Value().Elem()을 통하여 elements들을 가져옵니다. 그리고
elements.Type().Field()를 통하여 현재 필드의 데이터를 StructField형식으로 가져올 수 있습니다. StructField의 구조는 다음과 같습니다.
StructField의 구조
// A StructField describes a single field in a struct.
type StructField struct {
// Name is the field name.
Name string
// PkgPath is the package path that qualifies a lower case (unexported)
// field name. It is empty for upper case (exported) field names.
// See https://golang.org/ref/spec#Uniqueness_of_identifiers
PkgPath string
Type Type // field type
Tag StructTag // field tag string
Offset uintptr // offset within struct, in bytes
Index []int // index sequence for Type.FieldByIndex
Anonymous bool // is an embedded field
}
Name : 구조체 멤버 변수의 이름
Type : 구조체 맴버변수의 타입
Tag : 구조체 맴버변수의 태그
Offset : 구조체 멤버 변수의 오프셋(맴버변수의 메모리 위치)
Index : 구조체 맴버변수의 선언 순서
reflect를 이용하여 멤버 변수 가져오기
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Job string `json:"job"`
Salary int `json:"salary"`
}
func (p Person) Print() {
fmt.Println(p.Name, " is ", p.Job)
}
func (p *Person) SetSalary(salary int) {
p.Salary = salary
}
func (p Person) GetName() string {
return p.Name
}
func ShowMethod(i interface{}) {
value := reflect.ValueOf(i)
for index := 0; index < value.NumMethod(); index++ {
fmt.Printf("method name : %s\n", value.Type().Method(index).Name) // 1번
fmt.Printf("method type : %v\n\n", value.Method(index).Type()) // 2번
}
}
func main() {
p := &Person{
Name: "Han",
Age: 30,
Job: "Developer",
}
ShowMethod(p)
}
/* 출력결과
method name : GetName
method type : func() string
method name : Print
method type : func()
method name : SetSalary
method type : func(int)
*/
코드설명
1번 주석을 보면 Type().Method()를 통하여 구조체의 메서드의 타입을 가져올 수 있습니다. 가져온 메서드 타입으로 메서드 명을 가져올 수 있습니다.
2번 주석을 보면 Method().Type()을 통해 실제 메서드의 구성을 알 수 있습니다.
'Go언어' 카테고리의 다른 글
go work 사용해보기 (0) | 2023.07.06 |
---|---|
Ubuntu(Linux)에서 Go 재설치 (0) | 2022.10.30 |
Go언어 Cron (0) | 2021.06.15 |
Prometheus Go언어 Metric label (0) | 2021.06.14 |
Prometheus Go언어 Metric 생성 (0) | 2021.06.13 |