標準愚痴出力

個人的なIT作業ログです。もしかしたら一般的に参考になることが書いているかもしれません(弱気

つらい、さすがの reflect も構造体の非公開フィールドに値を無理やりセットする用途には使えないかー

package main

import (
    "reflect"
)

type privateOne struct {
    m1 string
    m2 string
}

func sub(from interface{}) interface{} {
    t := reflect.ValueOf(from).Elem().Type()
    obj := reflect.New(t)
    p := obj.Elem()
    p.Field(0).SetString("foo")
    p.Field(1).SetString("bar")
    return obj.Interface()
}

func main() {
    value := sub(&privateOne{"a", "b"})

    if val, ok := value.(*privateOne); ok {
        println(val.m1, val.m2)
    } else {
        println(reflect.TypeOf(value).String())
    }
}

実行してみよう!

$ ./privateStruct.exe
panic: reflect: reflect.Value.SetString using value obtained using unexported field

goroutine 1 [running]:
reflect.flag.mustBeAssignable(0x1b8)
    c:/go/src/reflect/value.go:231 +0x1fa
reflect.Value.SetString(0x478260, 0xc042052040, 0x1b8, 0x492f30, 0x3)
    c:/go/src/reflect/value.go:1551 +0x32
main.sub(0x473aa0, 0xc042052020, 0x0, 0x4660bc)
    C:/Users/hymko/go/src/github.com/zetamatta/experimental/privateStruct/main.go:16 +0x141
main.main()
    C:/Users/hymko/go/src/github.com/zetamatta/experimental/privateStruct/main.go:22 +0x97
exit status 2

普通に怒られた。ちなみに m1 → M1 、m2 → M2 などとフィールドの名前を変えると、期待動作する。

$ ./privateStruct.exe
foo bar

仕様動作を無理やり超えようとしたので、無理かなーとは思ってたんだが、やっぱりか!残念!(強引な解決が無理なら、ライブラリの開発元への「お願い」が通るのを期待するしかないなー)