Generic
https://github.com/usk81/generic

作った経緯とか

JavaとかのGeneric Typeとかとは違うんだけど、汎用型という意味で、Generic。
GoでWebサービス作ってると困るのが、JavaScriptとかGo以外のものとの連携で型があわないとか、RDBSとデータの受け渡しをする際にNULLをどうあつかうかとか、Goは単体だと書きやすいんだけど、他の言語とかが絡んできた途端に難しくなる気がする。

そういうことなので、nilを扱いやすくしたり、JsonをMarshal/Unmarshalするときに、ゆるく解釈してくれる型をつくりました。これでDB使うときにNull**型つかうか?それともポインタ型にするか問題の解決につながったり、JsonのMarshal/Unmarshalでエラーとかパニックとかの抑制になったりするといいんだけどね。

使い方

用意した型

  • TypeBool : nilも扱えるゆるいBoolean
  • TypeFloat : nilも扱えるゆるいFloat64
  • TypeInt : nilも扱えるゆるいInt64
  • TypeString : nilも扱えるゆるいString
  • TypeTime : nilも扱えるゆるいtime.Time
  • TypeUint : nilも扱えるゆるいUint64

例:TypeStringの場合

intだろうがbooleanだろうがfloatだろうが、json.Unmarshalの際にstring型に変換します。nullだったらnilになります。

type TestStringStruct struct {  
    Int       generic.TypeString `json:"int"`
    Float     generic.TypeString `json:"float"`
    Bool      generic.TypeString `json:"bool"`
    String    generic.TypeString `json:"string"`
    NullValue generic.TypeString `json:"null_value"`
}

func main() {  
    var ts TestStringStruct
    jstr := `{"int":10,"float":1.1,"bool":false,"string":"qwertyuiopkjhgv876","null_value":null}`
    expected := 
    json.Unmarshal([]byte(jstr), &ts)
    b, _ := json.Marshal(ts)
    fmt.Println(string(b))
    // {"int":"10","float":"1.1","bool":"false","string":"qwertyuiopkjhgv876","null_value":null}
}

例:TypeIntの場合

JSONじゃなくてもSetを使うことで単一の値も扱うことができます。

    var v string = "100"
    ti := generic.TypeInt{}
    ti.Set(v)
    val := ti.Value()
    fmt.Printf("%v (%T)", val, val)
    // 100 (int64)
}

TypeIntだったらこんなのがint64として扱えるようになります。

  • int, int8, int16, int32, int64
  • uint, uint8, uint16, uint32, uint64
  • float32, float64
  • bool
  • string (numericに限る)

その他

Scanも実装してるので、 db/sql にも対応できているはずです。