일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- http
- tcp
- go
- Python
- 책
- Sync
- range
- c++
- GO 언어
- windows
- Golang
- package
- File
- 리뷰
- JavaScript
- channel
- Callback
- window
- write
- mutex
- bitcoin
- json
- FOR
- Close
- C
- API
- 영화
- go언어
- Linux
- install
- Today
- Total
Code Habit
Go ) 리플렉션 본문
리플렉션은 실행시점(Runtime, 런타임)에 인터페이스나 구조체 등의 타입 정보를 얻어내거나 결정하는 기능이다.
package main
import {
"fmt"
"reflect"
}
type Data struct { // 구조체 정의
a, b int
}
func main() {
var num int = 1
fmt.Println(reflect.TypeOf(num)) // int
var s string = "Hello, world!"
fmt.Println(reflect.TypeOf(s)) // string
var f float32 = 1.3
fmt.Println(reflect.TypeOf(f)) // float32
var data Data = Data{1, 2}
fmt.Println(reflect.TypeOf(data)) // main.Data
}
|
reflect.TypeOf 함수를 사용하면 일반 자료형이나 구조체의 타입을 알 수 있다. ( Data 구조체는 main 패키지 안에 속해 있기 때문에 main.Data로 나온다.
리플렉션으로 구조체의 태그도 가져올 수 있다.
package main
import {
"fmt"
"reflect"
}
type Person struct {
name string 'tag1:"이름" tag2:"Name"' // 구조체의 태그 설정
age int 'tag1:"나이" tag2:"Age"' // 구조체의 태그 설정
}
func main() {
p := Person{}
name, ok := reflect.TypeOf(p).FieldByName("name")
fmt.Println(ok, name.Tag.Get("tag1"), name.Tag.Get("tag2")) // true 이름 Name
age, ok := reflect.TypeOf(p).FieldByName("age")
fmt.Println(ok, age.Tag.Get("tag1"), age.Tag.Get("tag2")) // true 나이 Age
}
|
구조체 필드의 태그는 '태그명:"내용"'형식으로 지정한다. 태그는 문자열 형태이며 문자열 안에 ""(따옴표)가 포함되므로 ''(백쿼트)로 감싸준다. 여러 개를 지정할 때는 공백으로 구분해준다.
reflect.TypeOf 함수에 구조체 인스턴스를 넣으면 reflect.Type이 리턴된다. 여기서 FieldByName 함수에 구조체의 필드 이름을 지정하면 필드 정보를 얻을 수 있다.
다음은 일반 포인터와 인터페이스의 값을 가져오는 방법이다.
package main
import {
"fmt"
"reflect"
}
func main() {
var a *int = new(int)
*a = 1
fmt.Println(reflect.TypeOf(a)) // *int
fmt.Println(reflect.ValueOf(a)) // <*int Value>
fmt.Println(reflect.ValueOf(a).Int()) // 런타임 에러
fmt.Println(reflect.ValueOf(a).Elem()) // <int Value>
fmt.Println(reflect.ValueOf(a).Elem().Int()) // 1
var b interface{}
b = 1
fmt.Println(reflect.TypeOf(b)) // int
fmt.Println(reflect.ValueOf(b)) // <int value>
fmt.Println(reflect.ValueOf(b).Int()) // 1
fmt.Println(reflect.ValueOf(b).Elem()) // 런타임 에러
}
|
포인터는 일반 변수와는 다르게 값을 가져오려면 reflect.ValueOf 함수로 값 정보 reflect.Value를 얻어온 뒤 다시 Elem 함수로 값 정보를 가져와야 한다. 그리고 변수 타입에 맞는 Int, Float, String 등의 함수로 값을 가져온다.
여기서 int 포인터 a의 값 정보에서 바로 Int함수로 값을 가져오려면 런타임 에러가 발생한다. 따라서 Elem 함수로 포인터의 메모리에 저장된 실제 값 정보를 가져와야 한다.
빈 인터페이스 b에 1을 대입하면 타입 정보는 int이고 값 정보는 int이다. 따라서 인터페이스의 값을 가져오려면 변수 타입에 맞는 Int, Float, String 등의 함수를 사용하면 된다.