Upgrade to Pro — share decks privately, control downloads, hide ads and more …

絶対にExportされてないフィールドを書き換えるなよ!絶対だぞ!絶対! / golang.tokyo#20

morikuni
December 18, 2018

絶対にExportされてないフィールドを書き換えるなよ!絶対だぞ!絶対! / golang.tokyo#20

morikuni

December 18, 2018
Tweet

More Decks by morikuni

Other Decks in Programming

Transcript

  1. About me • morikuni • https://twitter.com/inukirom • https://github.com/morikuni • Mercari

    Microservices Development • Go & Application Architecture • mercari.go に来て!
  2. Usage import ( "testing" "github.com/morikuni/go-experiment/overwrite" "github.com/morikuni/go-experiment/overwrite/internal" ) func TestField(t *testing.T)

    { x := internal.NewX("aaa") overwrite.Field(&x, "val", "bbb") if got, want := x.Get(), "bbb"; got != want { t.Errorf("got %v, want %v", got, want) } } package internal type X struct { val string } func (x X) Get()string { return x.val } func NewX(a string) X{ return X{a} }
  3. Implementation func Field(target interface{}, field string, val interface{}) error {

    targetVal := reflect.Indirect(reflect.ValueOf(target)) // セットするstructのreflect.Valueをとる if targetVal.Kind() != reflect.Struct { return ErrNotStruct } dstVal := targetVal.FieldByName(field) // セットするフィールドのreflect.Valueをとる if !dstVal.IsValid() { return ErrNoSuchField } srcVal := reflect.ValueOf(val) // セットする値のreflect.Valueをとる if srcVal.Type() != dstVal.Type() { return ErrTypeMismatch } dstAddr := unsafe.Pointer(dstVal.UnsafeAddr()) // セットするフィールドのアドレスをとる setableField := reflect.NewAt(dstVal.Type(), dstAddr).Elem() // セットするフィールドのアドレスにval型の変数を作成する setableField.Set(srcVal) // setableFieldはただの変数なので値をセットできる return nil }