21
reflect package in go lang 문용준 ( [email protected] )

Reflect package 사용하기

Embed Size (px)

Citation preview

Page 1: Reflect package 사용하기

reflect package in go lang

문용준([email protected])

Page 2: Reflect package 사용하기

리터럴 관리 기준

Type

Value

“harry potter”

33 int33

Type

Value

stringharry potter

프로그램 언어들에는 리터럴 즉 값을 데이터 타입별로 관리한다.

Page 3: Reflect package 사용하기

변수 정의

Type

Value

var s string s = “harry potter”

var x int x = 33 int

x

Type

Value

string

harry potter

변수

33

변수는 데이터 타입을로 정의하고 값을 저장하는 장소를 가진다.

s변수

Page 4: Reflect package 사용하기

reflection 이란

var x int x = 33 Type

Value

int

x변수

33

프로그램언어에서 reflection은 변수가 가진 데이터 타입을 인식하여 타입 캐스팅 등의 요건을 처리하는 구조

변수 x 의 타입을 처리reflect.TypeOf(x) reflect.ValueOf(x) 변수 x 의 Value값에 대한 타입을 처리

reflect.ValueOf(x).Int() 변수 x 의 Value에 대한 실제 값을처리

Page 5: Reflect package 사용하기

interface{}란

var all_type interface{} var xi int var xs string var xf float32

go lang에서 다른 데이터타입을 받아서 처리할 수 있는 데이터구조

all_type = xi fmt.Println(" int ", reflect.TypeOf(all_type)) all_type = xs fmt.Println(" string ", reflect.TypeOf(all_type)) all_type = xf fmt.Println(" float32 ", reflect.TypeOf(all_type))

Page 6: Reflect package 사용하기

예제: interface정의 및 구현(1/3)

type Stringer interface { String() string }

string을 처리하는 하나의 인터페이스 정의하고 타입을 정의하고 인터페이스를 구현함

type Binary uint64

// Binary는 Stringer 인터페이스를 구현한다. func (i Binary) String() string { return strconv.Itoa(i.Get()) }

//int 타입으로 변화 func (i Binary) Get() int { return int(i) }

Page 7: Reflect package 사용하기

예제: interface정의 및 구현(2/3)

func ToString(any interface{}) string {

switch vi := any.(type) { case uint64: return strconv.Itoa(int(vi)) case Binary: return strconv.Itoa(int(vi)) }

return "error" }

interface{}로 전달받아 처리하는 ToString함수를 정의

Page 8: Reflect package 사용하기

예제: interface정의 및 구현(3/3)

ffunc main() {

b := Binary(200) s := Stringer(b)

var c interface{} = b // 여기서 b 복사본을 만든다.

fmt.Println("string ", s.String()) fmt.Println(" bbbb", b) fmt.Println("ccccc ", c) fmt.Println("bbbbb string ", b.String()) fmt.Println("To String ", ToString(c)) fmt.Println(" String ", s.String())

}

실제 실행해조면 동일 한 값을 출력한다

Page 9: Reflect package 사용하기

itable: 인터페이스 테이블b 에 값을 넣고 b를 s에 인터페이스를 넣는다. 인테페이스 구조는 인터페이스 내의 데이터 타입과 실질적인 데이터 값을 저장하는 구조로 관리된다. 정의 메소드등이 있으면 인터페이스 itable에 메소드도 관리한다.

Page 10: Reflect package 사용하기

itable 컴퓨팅

가능한 모든 itable을 전부 미리 구성하는 것이 아닙니다. 구조를 만들면 실제 런타임에 실행하면서 처리합니다.

컴파일러는 각 타입에 대한 타입 구조 생성

컴파일러는 각 타입에 대한 메소드 구조 생성

런타임시 itable을 검색하여 메소드를 실행

Page 11: Reflect package 사용하기

빈 인터페이스 메모리구조

Page 12: Reflect package 사용하기

메모리 최적화: 두가지 케이스 조합

Page 13: Reflect package 사용하기

인터페이스 메모리 구조

Page 14: Reflect package 사용하기

리플렉션 법칙 (The Laws of Reflection)

Page 15: Reflect package 사용하기

Rob Pike의 리플렉션 법칙들

http://blog.golang/laws-of-reflection

reflect.TypeOf(interface {}) Type, reflect.ValueOf(interface{}) Value

1. 리플렉션은 인터페이스 값에서 리플렉션 오브젝트로 됩니다.

2. 리플렉션은 리플렉션 오브젝트에서 인터페이스 값으로 됩니다.

3. 리플렉션 오브텍드를 수정하려면 값은 설정할 수 있어야 됩니다.

canSet( ) bool => true 일 경우만 갱신

Page 16: Reflect package 사용하기

1. 리플렉션은 인터페이스 값에서 리플렉션 오브젝트로 됩니다.

var x float64 = 3.4

v := reflect.ValueOf(x)

fmt.Println(“type:”, v.Type())

fmt.Println(“kind is float64:”, v.Kind() == reflect.Float64)

fmt.Println(“value:”, v.Float())

//결과

type: float64

kind is float64: true

value: 3.4

Page 17: Reflect package 사용하기

유형(Type) 과 유형(Kind)

var x unit8 = ‘x’

v := reflect.ValueOf(x)

fmt.Println(“type:”, v.Type()) // unit8.

fmt.Print(“kind is unit8: ”,v.Kind() == reflect.Unit8) // true.

x = unit8(v.Unit()) // v.Unit returns a unit64.

type MyInt int

var x MyInt = 7

v := reflect.ValueOf(x)

fmt.Println(“kind is Int: ”, v.Kind() == reflect.Int) // true

Page 18: Reflect package 사용하기

2. 리플렉션은 리플렉션 객체에서 인터페이스 값으로 됩니다.

// Interface는 interface{} 처럼 v 값을 반환한다.

// func (v value) Interface() interface{}

y := v.Interface().(float64) // y는 float64 타입을 가질 것이다.

fmt.Println(y)

fmt.Printf(“value is %7.1e\n”, v.Interface()) // 3.4e+00

즉, 인터페이스 메소드는 ValueOf 함수의반대입니다. 그결과는 정적 타입 interface{} 입니다.

반복 : 리플렉션은 인터페이스 값에서 리플렉션 오브젝트로 되고 다시 반대로 됩니다.

Page 19: Reflect package 사용하기

3. 리플렉션 오브젝트를 수정하려면 값은 설정 가능할 수 있어야 합니다.

var x float64 = 3.4

v := reflect.ValueOf(x)

v.SetFloat(7.1) // 에러: 패닉이 올 것 입니다.

// 패닉 : reflect.Value.SetFloat 비주소적인 값을 이용

var x float64 = 3.4

v := reflect.ValueOf(x)

fmt.Println(“settability of v:”, v.CanSet())

// settability of v: false

“settability”는 무엇인가?

Page 20: Reflect package 사용하기

settability는 리플렉션 객체가 원래 항목을 가지고 있는 것에 따라 결정됩니다.

var x float64 = 3.4

// 우리는 여기에서 x이 복사본을 넘겨주고 있습니다.

v := reflect.ValueOf(x)

// f(x) 와 f(&x)의 다른점에 대하여 생각합니다.

// v.SetFloat(7.1) 내부의 리플렉션 값 복사된 값으로 변경됩니다.

그럼, 어떻게 리플렉션 값을 수정할 수 있을까요?

Page 21: Reflect package 사용하기

“포인터를 사용합니다, Luke”

var x float64 = 3.4

p := reflect.ValueOf(&x) // x 주소를 가져온다.

fmt.Println("type of p:", p.Type()) // type of p: *float64

fmt.Println("settability of p:", p.CanSet()) // settable of p: false

v := p.Elem()

fmt.Println(" vvvv ", v)

fmt.Println("settable of v:", v.CanSet())

v.SetFloat(7.1)

fmt.Println(v.Interface()) // 7.1

fmt.Println(x) //7.1