2017-03-08 13 views
3

Reflect를 사용하여 1.8의 unexported 필드에 액세스 할 수 있습니까? 이 더 이상 작동 것 같다 : https://stackoverflow.com/a/17982725/555493golang/unexport되지 않은 필드에 액세스 하시겠습니까?

참고 reflect.DeepEqual 작동하지만 나는 머리 또는 기능의 꼬리를 만들 수 없습니다 (즉, 그것은 안 export 필드에 액세스 할 수 있습니다) 잘. 작동중인 모습을 보여주는 go Playarea가 있습니다 : https://play.golang.org/p/vyEvay6eVG. 의 src 코드는 reflect 패키지의 안 export 기능에 액세스 할 수 있기 때문에

import (
"fmt" 
"reflect" 
) 

type Foo struct { 
    private string 
} 

func main() { 
    x := Foo{"hello"} 
    y := Foo{"goodbye"} 
    z := Foo{"hello"} 

    fmt.Println(reflect.DeepEqual(x,y)) //false 
    fmt.Println(reflect.DeepEqual(x,z)) //true 
} 

답변

1

reflect.DeepEqual()가 안 export 필드 값에 대한 액세스를 거부하는 safe 인수를 취하는 valueInterface() 기능에 대한 즉,이 경우에, 그것을 할 수 아래 safe=true 인 경우 Value.Interface() 방법을 통해 reflect.DeepEqual()safe=false을 전달할 것입니다.

아직 수행 할 수 있지만 내선이없는 필드에는 Value.Interface()을 사용할 수 없습니다. 대신 stringValue.String(), 부동 소수점에 Value.Float(), int에 Value.Int()과 같은 유형별 메서드를 사용해야합니다.이 메서드는 값의 복사본 (검사하기에 충분 함)을 반환하지만 사용자가 수정할 수는 없습니다 필드 값 (Value.Interface()이 작동하고 필드 유형이 포인터 유형일 경우 "부분적으로"가능할 수 있음).

필드가 인터페이스 유형일 경우, Value.Elem()을 사용하여 인터페이스 값에/포함 된 값으로 이동할 수 있습니다.

는 설명하기 위해 :

type Foo struct { 
    s string 
    i int 
    j interface{} 
} 

func main() { 
    x := Foo{"hello", 2, 3.0} 
    v := reflect.ValueOf(x) 

    s := v.FieldByName("s") 
    fmt.Printf("%T %v\n", s.String(), s.String()) 

    i := v.FieldByName("i") 
    fmt.Printf("%T %v\n", i.Int(), i.Int()) 

    j := v.FieldByName("j").Elem() 
    fmt.Printf("%T %v\n", j.Float(), j.Float()) 
} 

출력합니다 (Go Playground에 그것을 시도) : 구조체는 주소가

string hello 
int64 2 
float64 3 
+0

좋아하지만 어떻게 당신이 유형이되도록 무엇인지 알 수 있습니다 :이 트릭을 주소 지정되지 않은 구조체가 작동하지 않을 경우,하지만이 같은 주소 복사본을 만들 수 있습니다

올바른 방법을 호출 할 수 있습니까? –

+0

@UAvalos 예. 필드의 값에 대해 ['Value.Type()'] (https://golang.org/pkg/reflect/#Value.Type)을 호출하면됩니다. – icza

+0

정말 고통 스러울 정도의 스위치 블록이되지 않을까요? 예 : 사례 Uint, 사례 Uint8, Uint16 등 ... –

6

경우, 당신은 필드에 액세스 할 수 unsafe.Pointer을 사용할 수 있습니다 (을 읽거나 쓰기) 그것 같이, 이것 같이 :

rs := reflect.ValueOf(&MyStruct).Elem() 
rf := rs.Field(n) 
// rf can't be read or set. 
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem() 
// Now rf can be read and set. 

See full example on the playground.

unsafe.Pointer이 사용은 unsafe 패키지의 문서에 따라 "유효"이며, 깨끗하게 go vet들.

rs = reflect.ValueOf(MyStruct) 
rs2 := reflect.New(rs.Type()).Elem() 
rs2.Set(rs) 
rf = rs2.Field(0) 
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem() 
// Now rf can be read. Setting will succeed but only affects the temporary copy. 

See full example on the playground.

+0

눈부신 트릭, 고마워요. 'FieldByName'과 결합하여, 이것은 더럽지 만 꽤 강력합니다. – user1112789