最近Goを始めた新人Gopherです。
今まではRailsでWebアプリケーションを作ってました。
基本的にStructを定義していく感じか〜〜🤔フムフム
と読み方がだいたいわかってきたある日。
とあるサードパーティのサービスが返すJSONのプロパティ読みづらい!!
そのサードパーティ製ライブラリには以下のような定義がされてました。
Hoge.go
type Hoge struct {
Fuga map[string]interface{}
}
で、実際のオブジェクトはこんな感じ
{
"foo": {
"bar": {
"first": 1,
"second": 2
}
}
}
Interface{}・・・😭
できることならこんな感じで書きたい💡
first := hoge["foo"]["bar"]["first"] //=> 1
でもGoだとこう書かないといけない。
hoge.go
first := hoge["foo"].(map[string]interface{})["bar"].(map[string]interface{})["first"]
このままだとAPIの仕様変更でフォーマットが変わるたびにpanicしかねないので、
- nilチェック
- 型アサーション
はした方が良さそうですよね。(恐らく以下のような実装になると思います)
hoge.go
first := func() interface{} {
if foo := hoge["foo"]; foo != nil {
if _foo, ok := foo.(map[string]interface{}); ok {
if bar := _foo["bar"]; bar != nil {
if _bar, ok := bar.(map[string]interface{}); ok {
return _bar["first"]
}
}
}
}
return nil
}()
fmt.Println(first)
😭
Railsを思い出した
RailsだとActiveSupportの機能で
hoge.rb
first = hoge.try(:[], :foo).try(:[], :bar).try(:[], :first)
で取得でき、存在しないキーを参照していた場合nilが返却されます。安心安全☺️
ということで、
Goでも似たようなことができるライブラリを作りました!!
Go TryableMap
使い方
_tryable := tryablemap.NewTryableMap(hoge)
first := _tryable.Try("foo").Try("bar").Value("first")
fmt.Println(first) //=> 1
基本的には
- map[string]interface{}はとりあえずNewTryableMapに渡す
- 掘りたいパラメータはTryで掘り進め、取得したいパラメータはValueで取得する
- TryもValueも値が存在しなければnilを返す。
で掘る事ができます💡
- NewTryableArrayでArrayも安全に掘る事ができたり、
array.go
array := [][]int{
[]int{1, 2, 3}, []int{4, 5, 6}, []int{7, 8, 9},
}
tryable := tryablemap.NewTryableArray(array)
result := tryable.TryArray(0).Value(0) //=> 1
以下のようなArrayとMapが混ざっている場合は、
arraymap.json
{
"hoge": [
{ "first": [1, 2, 3] },
{ "second": [4, 5, 6] }
]
}
- TryとTryArrayを使い分ける事で掘る事ができます😆
arraymap.go
tryable := tryablemap.NewTryableMap(arraymap)
first := tryable.TryArray("hoge").Try(0).TryArray("first").Value(0)
fmt.Println(first) //=> 1
Tryは返却値がMapのときに使い、TryArrayはArrayのときに使うイメージです。
Value関数の引数keyはMapの時はString、Arrayの時はIntを渡すことになります。
安全な芋掘りでより良いGoライフを!
.