@kyanny's blog

商品にならぬ技術は役に立たない - トーマス・エジソン

Go: struct リテラルを返す関数

戻り値の型も同じものを書けば(冗長だが)いける。

package main

import "fmt"

func f() struct{Msg string} {
    return struct{
        Msg string
    }{
        Msg: "Yo",
    }
}

func g() *struct{Msg string} {
    return &struct{
        Msg string
    }{
        Msg: "Go",
    }
}

func main() {
    fmt.Printf("%#v\n", f().Msg)
    fmt.Printf("%#v\n", g().Msg)
}

実験結果

https://play.golang.org/p/Kq6-RJp-VZd

Go で PostgreSQL の JSON/JSONB データ型を扱う

PostgreSQL 側で JSON/JSONB 型としてフィールドが定義されていれば、 Go プログラムからは string なり []byte なりを INSERT するだけで良い。

dataString := `{"a":"A","b":"B"}`
_, err = db.Exec("insert into t (dataType, json, jsonb) values($1, $2, $3)", "string", dataString, dataString)

dataBytes := []byte(`{"a":"A","b":"B"}`)
_, err = db.Exec("insert into t (dataType, json, jsonb) values($1, $2, $3)", "[]byte", dataBytes, dataBytes)

SELECT するとき rows.Scan() に渡す型に応じて string なり []byte なりで取得できる。

rows, err := db.Query("select dataType, json, jsonb from t")
for rows.Next() {
    var dataType string
    var json string
    var jsonb string
    rows.Scan(&dataType, &json, &jsonb)
    fmt.Printf("%s %#v %#v\n", dataType, json, jsonb)
}

rows, err = db.Query("select dataType, json, jsonb from t")
for rows.Next() {
    var dataType string
    var json []byte
    var jsonb []byte
    rows.Scan(&dataType, &json, &jsonb)
    fmt.Printf("%s %#v %#v\n", dataType, json, jsonb)
}

Full code snippet (PostgreSQL サーバを起動しておく必要あり)

https://play.golang.org/p/ViHTxu7poOp

string "{\"a\":\"A\",\"b\":\"B\"}" "{\"a\": \"A\", \"b\": \"B\"}"
[]byte "{\"a\":\"A\",\"b\":\"B\"}" "{\"a\": \"A\", \"b\": \"B\"}"
string []byte{0x7b, 0x22, 0x61, 0x22, 0x3a, 0x22, 0x41, 0x22, 0x2c, 0x22, 0x62, 0x22, 0x3a, 0x22, 0x42, 0x22, 0x7d} []byte{0x7b, 0x22, 0x61, 0x22, 0x3a, 0x20, 0x22, 0x41, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x22, 0x3a, 0x20, 0x22, 0x42, 0x22, 0x7d}
[]byte []byte{0x7b, 0x22, 0x61, 0x22, 0x3a, 0x22, 0x41, 0x22, 0x2c, 0x22, 0x62, 0x22, 0x3a, 0x22, 0x42, 0x22, 0x7d} []byte{0x7b, 0x22, 0x61, 0x22, 0x3a, 0x20, 0x22, 0x41, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x22, 0x3a, 0x20, 0x22, 0x42, 0x22, 0x7d}

ちゃんと JSON/JSONB 型として保存されているので、 JSON 演算子が使える。

postgres=# select json->'a', jsonb->'b' from t;
 ?column? | ?column?
----------+----------
 "A"      | "B"
 "A"      | "B"
(2 rows)

Go を書き始めて二週間ほど経つ。現時点では総じてつらい。わからないことが多すぎる。何がわからないのか言語化できないので思いつくキーワードで調べた結果をひたすら読むしかなく、効率が悪い。わからないことが芋づる式に出てくるので読めば読むほどインプットが増え、理解が追いつかなくなる。時間をかけた割に初歩的な FAQ だったりすると検索能力の低さも相まって非常に落ち込む。

Go: json Encode() は末尾に改行文字がつく

go - Why does json.Encoder add an extra line? - Stack Overflow

*json.Encoder はストリーム処理用で、区切りとして \n をつけると。そういうものらしい。

改行文字を取り除くには strings.TrimSuffix() を使う。

ドキュメントにも書いてある。

https://golang.org/pkg/encoding/json/#Encoder.Encode

ソースコード

https://golang.org/src/encoding/json/stream.go?s=5070:5117#L191


> をエスケープしていない JSON をリクエストボディにしたら末尾に改行文字がついたせいでシグネチャの計算値が変わってしまい、とある API の呼び出しがエラーになって少しハマった。


実験結果

https://play.golang.org/p/IfpoAOUFnMq