{"id":16687663,"url":"https://github.com/pei0804/go-tips","last_synced_at":"2026-02-07T01:31:15.714Z","repository":{"id":139120960,"uuid":"111878673","full_name":"pei0804/go-tips","owner":"pei0804","description":null,"archived":false,"fork":false,"pushed_at":"2018-02-13T11:01:06.000Z","size":15,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-13T17:26:37.447Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pei0804.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-11-24T05:15:53.000Z","updated_at":"2017-11-24T05:15:53.000Z","dependencies_parsed_at":null,"dependency_job_id":"33100393-81b2-4c91-b4ee-2098df715c68","html_url":"https://github.com/pei0804/go-tips","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pei0804/go-tips","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pei0804%2Fgo-tips","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pei0804%2Fgo-tips/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pei0804%2Fgo-tips/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pei0804%2Fgo-tips/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pei0804","download_url":"https://codeload.github.com/pei0804/go-tips/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pei0804%2Fgo-tips/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29183947,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-07T00:44:15.062Z","status":"ssl_error","status_checked_at":"2026-02-07T00:35:01.758Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-12T15:24:35.822Z","updated_at":"2026-02-07T01:31:15.674Z","avatar_url":"https://github.com/pei0804.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# GO TIPS\n\n## Middlewareに引数を渡せるようにする\n\n```go\nfunc Auth(db string) (fn func(http.Handler) http.Handler) {\n\tfn = func(h http.Handler) http.Handler {\n\t\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\tfmt.Println(db)\n\t\t\th.ServeHTTP(w, r)\n\t\t})\n\t}\n\treturn\n}\n```\n\n## 型変換\n\n### string -\u003e int\n\n```go\nvar i int\ni, _ = strconv.Atoi(\"255\")\nfmt.Println(i)  // =\u003e 255\n```\n\n### string -\u003e bool\n\n```go\nvar b bool\nb, _ = strconv.ParseBool(\"true\")\nfmt.Println(b) // =\u003e true\n```\n\n### string -\u003e int any\n\n```go\nvar i32, i64, ib16, ib0 int64\ni32, _ = strconv.ParseInt(\"255\", 10, 32)\ni64, _ = strconv.ParseInt(\"255\", 10, 64)\nib16, _ = strconv.ParseInt(\"ff\", 16, 16)\nib0, _ = strconv.ParseInt(\"0xff\", 0, 16)\nfmt.Println(i32, i64, ib16, ib0)   // =\u003e 255 255 255 255\n```\n\n### string -\u003e uint\n\n```go\nvar ui uint64\nui, _ = strconv.ParseUint(\"255\", 10, 32)\nfmt.Println(ui) // =\u003e 255\n```\n\n### string -\u003e float\n\n```go\nvar f32, f64 float64\nf32, _ = strconv.ParseFloat(\"3.14159265359\", 32)\nf64, _ = strconv.ParseFloat(\"3.14159265359\", 64)\nfmt.Println(f32, f64) // =\u003e 3.1415927410125732 3.14159265359\n```\n\n### parse err\n\n```go\n_, e = strconv.ParseInt(\"Bad number\", 10, 32)\nif e != nil {\n  if enum, ok := e.(*strconv.NumError); ok {\n    switch enum.Err {\n    case strconv.ErrRange:\n      log.Fatal(\"Bad Range Error\")\n    case strconv.ErrSyntax:\n      log.Fatal(\"Syntax Error\")\n    }\n  }\n}\n```\n\n### any -\u003e string\n\n```go\nfmt.Sprint(hoge)\n```\n\n## HTTP\n\n### Header\n\n```go\nfunc Hoge(w http.ResponseWriter, req *http.Request) {\n    Hoge := req.Header.Get(\"Hoge\")\n}\n```\n\n```go\nreq.Header.Set(\"Hoge\") = \"hoge\"\n```\n\n### Debug\n\n```go\npackage main\n\nimport (\n    \"encoding/json\"\n    \"fmt\"\n    \"io\"\n    \"log\"\n    \"net/http\"\n    \"os\"\n)\n\ntype Foo struct {\n    ID  string `json:\"id\"`\n    Content string `json:\"content\"`\n}\n\nfunc main() {\n    resp, err := http.Get(\"http://example.com\")\n    if err != nil {\n        log.Fatal(err)\n    }\n    defer resp.Body.Close()\n\n    var r io.Reader = resp.Body\n    r = io.TeeReader(r, os.Stderr)\n\n    var foo Foo\n    err = json.NewDecoder(r).Decode(\u0026foo)\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    fmt.Println(foo.Content)\n}\n```\n\n## map\n\n### nest strcut\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n)\n\ntype Stats struct {\n    cnt      int\n    category map[string]Events\n}\n\ntype Events struct {\n    cnt   int\n    event map[string]*Event\n}\n\ntype Event struct {\n    value int64\n}\n\nfunc main() {\n\n    stats := new(Stats)\n    stats.cnt = 33\n    stats.category = make(map[string]Events)\n    e, f := stats.category[\"aa\"]\n    if !f {\n        e = Events{}\n    }\n    e.cnt = 66\n\n    e.event = make(map[string]*Event)\n    stats.category[\"aa\"] = e\n    stats.category[\"aa\"].event[\"bb\"] = \u0026Event{}\n    stats.category[\"aa\"].event[\"bb\"].value = 99\n\n    fmt.Println(stats)\n    fmt.Println(stats.cnt, stats.category[\"aa\"].event[\"bb\"].value)\n}\n```\n\n### nest map\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tdata := map[string]map[string]int{\n\t\t\"first\": map[string]int{},\n\t}\n\tdata[\"first\"][\"one\"] = 1\n\tdata[\"first\"][\"two\"] = 2\n\tfmt.Println(data)\n    // -\u003e map[first:map[two:2 one:1]]\n\n\t// bad\n\t// data[\"second\"][\"one\"] = 1\n\n\tdata[\"first\"] = map[string]int{\"three\": 3}\n\tfmt.Println(data)\n    // -\u003e map[first:map[three:3]]\n}\n```\n\n### struct map\n\n```go\npackage main\n\nimport \"fmt\"\n\ntype myStruct struct {\n    atrib1 string\n    atrib2 string\n}\n\ntype mapKey struct {\n    Key    string\n    Option string\n}\n\nfunc main() {\n    apiKeyTypeRequest := make(map[mapKey]myStruct)\n\n    apiKeyTypeRequest[mapKey{\"Key\", \"MyFirstOption\"}] = myStruct{\"first Value first op\", \"second Value first op\"}\n    apiKeyTypeRequest[mapKey{\"Key\", \"MysecondtOption\"}] = myStruct{atrib1: \"first Value second op\"}\n\n    fmt.Printf(\"%+v\\n\", apiKeyTypeRequest)\n}\n```\n\n### struct map init\n\n```go\ntype myStruct struct {\n      atrib1 string\n      atrib2 string\n}\n\nfunc main() {\n    var myMap = map[string]map[string]myStruct{\n        \"foo\": {\n            \"bar\": {attrib1: \"a\", attrib2: \"b\"},\n            \"baz\": {\"c\", \"d\"}, //or by order...\n        },\n        \"bar\": {\n            \"gaz\": {\"e\", \"f\"},\n            \"faz\": {\"g\", \"h\"},\n        },\n    }\n    fmt.Println(myMap[\"foo\"][\"bar\"].atrib1)\n    fmt.Println(myMap[\"bar\"][\"gaz\"].atrib2)\n}\n```\n\n## struct\n\n### init\n\n```go\nusers := []struct {\n  ID   int    `json:\"id\"`\n  User string `json:\"user\"`\n}{\n  {1, \"hoge\"},\n  {2, \"foo\"},\n  {3, \"bar\"},\n}\n```\n\n## slice\n\n### copy\n\n```go\nnewSlice := make([]newType, len(oldSlice))\nfor i,v := range oldSlice {\n    newSlice[i] = newType{\n        field1: v.oldField1,\n        field2: v.oldField2,\n    }\n}\n```\n\n### Pointer\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tvar s = \u0026[]string{\"1\", \"2\", \"3\"}\n\tmodifySlice(s)\n\tfmt.Println(s)\n}\n\nfunc modifySlice(i *[]string) {\n\tp := *i\n\tfmt.Println(len(p))\n\t*i = append(*i, \"4\")\n}\n```\n\n```console\n3\n\u0026[1 2 3 4]\n```\n\n### Value\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tvar s = []string{\"1\", \"2\", \"3\"}\n\tmodifySlice(s)\n\tfmt.Println(s[0])\n\tfmt.Println(s)\n}\n\nfunc modifySlice(i []string) {\n\ti[0] = \"3\"\n\ti = append(i, \"4\")\n}\n```\n\n```console\n3\n[3 2 3]\n```\n\nスライス引数の内容は関数で変更できますが、そのヘッダは変更できません。スライス変数に格納された長さは、関数の呼び出しによって変更されません。これは、関数がオリジナルではなくスライスヘッダのコピーを渡されるためです。したがって、ヘッダーを変更する関数を記述したい場合は、ここで行ったように、ヘッダーを結果パラメーターとして返す必要があります。\n\n## error\n\n### Wrap()\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/pkg/errors\"\n)\n\nfunc main() {\n\terr := doSomething()\n\tif err != nil {\n\t\tDebugf(\"%+v\\n\", err)\n\t}\n}\n\nfunc Debugf(format string, args ...interface{}) {\n\tfmt.Fprintf(os.Stdout, \"[DEBUG] \"+format+\"\\n\", args...)\n}\n\nfunc doSomething() error {\n\terr := read()\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"faild\")\n\t}\n\treturn nil\n}\n\nfunc read() error {\n\treturn fmt.Errorf(\"エラー\")\n}\n```\n\n```console\n*SomeError\nCode: 400, Message: invalid open\n```\n\n### Cause()\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/pkg/errors\"\n)\n\nfunc main() {\n\tif err := doSomething(); err != nil {\n\t\tswitch errors.Cause(err).(type) {\n\t\tcase *SomeError:\n\t\t\tfmt.Fprintln(os.Stderr, \"*SomeError\")\n\t\tdefault:\n\t\t}\n\t\tfmt.Fprintln(os.Stderr, err)\n\t\treturn\n\t}\n}\n\ntype SomeError struct {\n\tCode    int\n\tMessage string\n}\n\nfunc (s *SomeError) Error() string {\n\treturn fmt.Sprintf(\"Code: %d, Message: %s\", s.Code, s.Message)\n}\n\nfunc doSomething() error {\n\treturn open()\n}\n\nfunc open() error {\n\treturn \u0026SomeError{Code: 400, Message: \"invalid open\"}\n}\n```\n\n```console\n[DEBUG]エラー\nfaild\nmain.doSomething\n\t/Users/jumpei/go/src/github.com/pei0804/go-chi-api-example/err/err1/err1.go:24\nmain.main\n\t/Users/jumpei/go/src/github.com/pei0804/go-chi-api-example/err/err1/err1.go:11\nruntime.main\n\t/Users/jumpei/.anyenv/envs/goenv/versions/1.8/src/runtime/proc.go:185\nruntime.goexit\n\t/Users/jumpei/.anyenv/envs/goenv/versions/1.8/src/runtime/asm_amd64.s:2197\n```\n\n## Template\n\n```html\n\u003chtml\u003e\n\n  {{/* コメント*/}}\n\n  {{/* ドット名前でgoから受け取れる */}}\n  \u003ch1\u003e{{.a}}\u003c/h1\u003e\n\n  {{/* ループはrange, ドットで要素にアクセス, endで終了 */}}\n  \u003cul\u003e\n    {{range .b}}\n    \u003cli\u003e{{.}}\u003c/li\u003e\n    {{end}}\n  \u003c/ul\u003e\n\n  {{/* 構造体は、ドットにメンバ名でアクセス */}}\n  {{range .c}}\n  \u003cp\u003e{{.Id}}\u003cb\u003e{{.Name}}\u003c/b\u003e\u003c/p\u003e\n  {{end}}\n\n  {{/* 構造体、ループなしなら, ドット変数ドットメンバ */}}\n  \u003cp\u003e{{.d.Id}}\u003cb\u003e{{.d.Name}}\u003c/b\u003e\u003c/p\u003e\n\n  {{/* if文 */}}\n  {{if .e}}\n  \u003cp\u003e e true \u003c/p\u003e\n  {{else}}\n  \u003cp\u003e e false \u003c/p\u003e\n  {{end}}\n\n  {{if .f}}\n  \u003cp\u003e f true \u003c/p\u003e\n  {{else}}\n  \u003cp\u003e f false \u003c/p\u003e\n  {{end}}\n\n  {{/* goソースでgは指定されていない */}}\n  {{if .g}}\n  \u003cp\u003e g true \u003c/p\u003e\n  {{else}}\n  \u003cp\u003e g false \u003c/p\u003e\n  {{end}}\n\n  {{/* withはifが真の場合、ドットに情報が設定される */}}\n  {{with .h}}\n  \u003cp\u003e h1 {{.}} \u003c/p\u003e\n  {{end}}\n\n  {{/* withでなくif使うと、ドットアクセスで特定要素が出力されず */}}\n  {{if .h}}\n  \u003cp\u003e h2 {{.}} \u003c/p\u003e\n  {{end}}\n\n  {{/* 変数宣言できる */}}\n  {{/* printf など関数使用可能。fmt.Printfのエイリアス */}}\n  {{$i := \"ii\"}}\n  \u003cp\u003e{{$i}}\u003c/p\u003e\n  \u003cp\u003e{{printf \"%s-%s\" $i \"iii\"}}\u003c/p\u003e\n\n  {{/* defineで定義することも可 */}}\n  {{define \"J\"}}\n  \u003cp\u003ejjj\u003c/p\u003e\n  {{end}}\n\n  \u003chr\u003e\n\n  {{/* defineで定義された呼び出しはtemplate */}}\n  {{template \"J\"}}\n\n  {{/* 不等号比較など、小なりはlt */}} \n  {{$k := 8}}\n  {{if lt 5 $k}}\n  \u003cp\u003e 8 large \u003c/p\u003e\n  {{else}}\n  \u003cp\u003e 5 large \u003c/p\u003e\n  {{end}}\n\n\u003c/html\u003e\n```\n\n## DEBUG\n\n```go\npackage main\n\nimport (\n    \"log\"\n)\n\ntype Foo struct {\n    Bar string\n    Baz string\n}\n\nfunc main() {\n    foo := \u0026Foo{\"bar\", \"baz\"}\n    log.Printf(\"%v\", foo)\n    log.Printf(\"%+v\", foo)\n    log.Printf(\"%#v\", foo)\n    log.Printf(\"%T\", foo)\n}\n```\n\n```console\n2013/12/11 21:52:10 \u0026{bar baz}\n2013/12/11 21:52:10 \u0026{Bar:bar Baz:baz}\n2013/12/11 21:52:10 \u0026main.Foo{Bar:\"bar\", Baz:\"baz\"}\n2013/12/11 21:52:10 *main.Foo\n```\n\n# DB\n\n## unknown column\n\n[gist](https://gist.github.com/SchumacherFM/69a167bec7dea644a20e)\n\n```go\n\npackage main\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t_ \"github.com/go-sql-driver/mysql\"\n\t\"log\"\n)\n\nconst (\n\t// 1745 rows\n\t// columns are: value_id, entity_type_id, attribute_id, store_id, entity_id, value\n\tTEST_QUERY = `SELECT * FROM catalog_product_entity_varchar`\n)\n\nfunc main() {\n\tdb, err := sql.Open(\"mysql\", \"magento-1-8:magento-1-8@tcp(:3306)/magento-1-8\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tdefer db.Close()\n\n\trows, err := db.Query(TEST_QUERY)\n\tfck(err)\n\tdefer rows.Close()\n\tcolumnNames, err := rows.Columns()\n\tfck(err)\n\trc := NewMapStringScan(columnNames)\n\tfor rows.Next() {\n\t\t//        cv, err := rowMapString(columnNames, rows)\n\t\t//        fck(err)\n\t\terr := rc.Update(rows)\n\t\tfck(err)\n\t\tcv := rc.Get()\n\t\tlog.Printf(\"%#v\\n\\n\", cv)\n\t}\n}\n\n/**\n  using a map\n*/\ntype mapStringScan struct {\n\t// cp are the column pointers\n\tcp []interface{}\n\t// row contains the final result\n\trow      map[string]string\n\tcolCount int\n\tcolNames []string\n}\n\nfunc NewMapStringScan(columnNames []string) *mapStringScan {\n\tlenCN := len(columnNames)\n\ts := \u0026mapStringScan{\n\t\tcp:       make([]interface{}, lenCN),\n\t\trow:      make(map[string]string, lenCN),\n\t\tcolCount: lenCN,\n\t\tcolNames: columnNames,\n\t}\n\tfor i := 0; i \u003c lenCN; i++ {\n\t\ts.cp[i] = new(sql.RawBytes)\n\t}\n\treturn s\n}\n\nfunc (s *mapStringScan) Update(rows *sql.Rows) error {\n\tif err := rows.Scan(s.cp...); err != nil {\n\t\treturn err\n\t}\n\n\tfor i := 0; i \u003c s.colCount; i++ {\n\t\tif rb, ok := s.cp[i].(*sql.RawBytes); ok {\n\t\t\ts.row[s.colNames[i]] = string(*rb)\n\t\t\t*rb = nil // reset pointer to discard current value to avoid a bug\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"Cannot convert index %d column %s to type *sql.RawBytes\", i, s.colNames[i])\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (s *mapStringScan) Get() map[string]string {\n\treturn s.row\n}\n\n/**\n  using a string slice\n*/\ntype stringStringScan struct {\n\t// cp are the column pointers\n\tcp []interface{}\n\t// row contains the final result\n\trow      []string\n\tcolCount int\n\tcolNames []string\n}\n\nfunc NewStringStringScan(columnNames []string) *stringStringScan {\n\tlenCN := len(columnNames)\n\ts := \u0026stringStringScan{\n\t\tcp:       make([]interface{}, lenCN),\n\t\trow:      make([]string, lenCN*2),\n\t\tcolCount: lenCN,\n\t\tcolNames: columnNames,\n\t}\n\tj := 0\n\tfor i := 0; i \u003c lenCN; i++ {\n\t\ts.cp[i] = new(sql.RawBytes)\n\t\ts.row[j] = s.colNames[i]\n\t\tj = j + 2\n\t}\n\treturn s\n}\n\nfunc (s *stringStringScan) Update(rows *sql.Rows) error {\n\tif err := rows.Scan(s.cp...); err != nil {\n\t\treturn err\n\t}\n\tj := 0\n\tfor i := 0; i \u003c s.colCount; i++ {\n\t\tif rb, ok := s.cp[i].(*sql.RawBytes); ok {\n\t\t\ts.row[j+1] = string(*rb)\n\t\t\t*rb = nil // reset pointer to discard current value to avoid a bug\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"Cannot convert index %d column %s to type *sql.RawBytes\", i, s.colNames[i])\n\t\t}\n\t\tj = j + 2\n\t}\n\treturn nil\n}\n\nfunc (s *stringStringScan) Get() []string {\n\treturn s.row\n}\n\n// rowMapString was the first implementation but it creates for each row a new\n// map and pointers and is considered as slow. see benchmark\nfunc rowMapString(columnNames []string, rows *sql.Rows) (map[string]string, error) {\n\tlenCN := len(columnNames)\n\tret := make(map[string]string, lenCN)\n\n\tcolumnPointers := make([]interface{}, lenCN)\n\tfor i := 0; i \u003c lenCN; i++ {\n\t\tcolumnPointers[i] = new(sql.RawBytes)\n\t}\n\n\tif err := rows.Scan(columnPointers...); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor i := 0; i \u003c lenCN; i++ {\n\t\tif rb, ok := columnPointers[i].(*sql.RawBytes); ok {\n\t\t\tret[columnNames[i]] = string(*rb)\n\t\t} else {\n\t\t\treturn nil, fmt.Errorf(\"Cannot convert index %d column %s to type *sql.RawBytes\", i, columnNames[i])\n\t\t}\n\t}\n\n\treturn ret, nil\n}\n\nfunc fck(err error) {\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\n## Tx\n\n[Structuring Applications in Go](https://medium.com/@benbjohnson/structuring-applications-in-go-3b04be4ff091)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpei0804%2Fgo-tips","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpei0804%2Fgo-tips","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpei0804%2Fgo-tips/lists"}