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. 絶対にExportされてないフィールドを書き換える
    なよ!絶対だぞ!絶対!
    golang.tokyo #20

    View full-size slide

  2. About me
    ● morikuni
    ● https://twitter.com/inukirom
    ● https://github.com/morikuni
    ● Mercari Microservices Development
    ● Go & Application Architecture
    ● mercari.go に来て!

    View full-size slide

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

    View full-size slide

  4. 「あれ?Exportされてないフィールドってそ
     もそも書き換えられないよね?何言ってる 
     の?」
    Goの有識者の声

    View full-size slide

  5. 書き換えに成功して
    しまいまいした。
    大変申し訳ありませんが
    github.com/morikuni/go-experiment/overwrite

    View full-size slide

  6. 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}
    }

    View full-size slide

  7. 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
    }

    View full-size slide

  8. まとめ
    ● Exportされていないフィールドを書き換えました
    ● 絶対に本番環境ではつかうなよ!絶対だぞ!絶対!

    View full-size slide