golang メモ

golang についてのメモ。適宜追加。

The Go Programming Language

目次

組み込み関数

ドキュメント

下記にまとまっている。

builtin - The Go Programming Language

string

アクセス方法ごとの返り値

...で展開した際はbyteが返るので、下記のようにしてbyte sliceにappendできる。

   a := []byte{}
    b := "hoge"
    a = append(a, b...)

stringは配列のようにアクセスするとbyteが返る。またstringのサイズをlenで求めた場合、byte数が返る。

一方で、for rangeで回すとruneが返る。

よって、下記のようにループの回し方でそれぞれ異なる値が返る。

package main

import "fmt"

func main() {
    test := "hoge"

    for i := 0; i < len(test); i++ {
        fmt.Printf("type=%T val=%x\n", test[i], test[i])
    }

    for _, v := range test {
        fmt.Printf("type=%T val=%c\n", v, v)
    }

}
type=uint8 val=68
type=uint8 val=6f
type=uint8 val=67
type=uint8 val=65
type=int32 val=h
type=int32 val=o
type=int32 val=g
type=int32 val=e

slice

lengthとcapacity

sliceはlengthとcapacity を持つ。それぞれlen() および cap() というビルトイン関数で取得できる。いずれも戻り値はint型。

makeする際にcapcityを省略すると、capacityの値はlengthと等しくなる。

   a := make([]int, 8)
    fmt.Printf("len=%d cap=%d\n", len(a), cap(a))
    // len=8 cap=8

sliceは参照型

参照型なので、代入してから変更すると、元のsliceも更新される。

func printSlicePointer() {
    a := []byte{0xaa}
    b := a

    fmt.Printf("a=%p b=%p\n a=%x\n b=%x\n", a, b, a, b)

    b[0] = 0x12

    fmt.Printf("a=%p b=%p\n a=%x\n b=%x\n", a, b, a, b)

}

これの結果は下記。アドレスならびにbへの修正がaに対しても行われたかのように見える。

a=0xc00001a110 b=0xc00001a110
 a=aa
 b=aa
a=0xc00001a110 b=0xc00001a110
 a=12
 b=12

これを避けるにはcopyを使用して、同一内容のsliceを別途作成する。

sliceのcopy

// copy元のslice が var src []byteとする
dst := make([]byte, len(src) )
copy(dst, src)

dstに十分なlengthがない場合、copyでpanicする。

sliceの一部を参照する

dst := src[start:end]

これによって、src[start] から src[end-1]の要素を参照する slice dst が生成される。len(dst) は end - startとなる。

参照なので、dstを修正した場合は、src側も修正される。

startとendは省略も可能。startを省略した場合は先頭から、endを省略した場合は最後尾まで、という意味になる。

array

宣言

下記のように書くことで、要素数コンパイラが決めてくれる。

   a := [...]int{0, 1, 2, 3}

arrayを参照するsliceの生成

slice := array[:]

下記のようなコードを実行すると、sliceとarrayで同じアドレスを指しており、sliceはarrayの参照であることがわかる。

   a := [4]int{0, 1, 2, 3}
    b := a[:]
    fmt.Printf("a=%p b=%p\n a=%x\n b=%x\n", &a, b, a, b)

この結果は下記。

a=0xc000014460 b=0xc000014460
 a=[0 1 2 3]
 b=[0 1 2 3]

interface

cast

vInt, ok := i.(int)

switch

   switch v := i.(type) {
    case int:
        fmt.Printf("int\n")
    case string:
        fmt.Printf("string\n")
    default:
        fmt.Printf("unknown\n")
    }

構造体のTag

encoding/json でよく見る。`key:"val"`

   type sample struct {
        i int     `json:"int"`
        f float32 `sample:"float"`
    }

バッククォート内ではスペースをつけて複数のタグを付与することもできる。

   type sample struct {
        i int     `json:"int" sample:"aaa"`

The Go Programming Language Specification - The Go Programming Language

タグの取得

reflectパッケージを使用する。reflect.StructFieldを取得し、そのメンバのTagを参照する。

  1. TypeOfでTypeを取得
  2. Kindで構造体か判別し、NumFieldで構造体個数を確認する。
  3. Fieldで構造体メンバを取得し、TagメンバのStructTagに対して、Get/Lookupする。
func readStructTag() {
    type S struct {
        V int    `sample:"V"`
        W string `sample:"W"`
        I uint
        B float32 `sample:""`
    }
    s := S{}
    t := reflect.TypeOf(s)
    for i := 0; i < t.NumField(); i++ {
        f := t.Field(i)
        v, ok := f.Tag.Lookup("sample")
        if ok {
            fmt.Printf("%d:value=%s\n", i, v)
        }
    }
}
0:value=V
1:value=W
3:value=

reflect - The Go Programming Language

cgo

公式Wiki

cgo · golang/go Wiki · GitHub

テスト

$ go test

サブディレクトリ以下もテストをする場合は、./...を付与する。

$ go test ./...

コメントによる標準出力のテスト

// Output: というコメントを付与し、改行後想定される出力をコメントで記述する。 // の後にはスペースを挟む。

// Output:
// 0x0f

出力内容が順不同の場合は、// Unordered output: とする。

testing - The Go Programming Language

ベンチマーク

BenchmarkXxx(*testing.B) という関数を定義する。 Xxxとあるように、大文字である必要がある。

testing - The Go Programming Language

go test にオプションを付与することでベンチマークが測定される。

go - The Go Programming Language

メモリ使用量やアロケート回数を調べたい場合は下記。

go test -bench . --benchmem

プロファイルを取得する

[Go] pprofでのプロファイル(計測)のやり方を改めて整理した - Qiita

go test時に下記オプションを付与することで、go tool pprof 用のファイルを生成できる。

go test -cpuprofile cpu.prof -memprofile mem.prof -bench .

ビルド

Cから使える共有ライブラリをビルドする

-buildmode=c-shared を付与する。

go - The Go Programming Language

最適化状況を確認する

-gcflags "-m" をつける。

Goのコンパイル時の最適化結果を確認する(インライン化の条件についても記載) - Qiita

最適化されるための条件。

CompilerOptimizations · golang/go Wiki · GitHub

コンパイルオプション一覧

compile - The Go Programming Language

golang 自体のビルド

リポジトリをチェックアウトして、バージョンbranchにスイッチ。

$ git clone https://go.googlesource.com/go goroot
$ cd goroot
$ git checkout go1.XX.X
$ cd src
$ ./all.bash

参考資料