Data Types

基本型

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // uint8 の別名

rune // int32 の別名
     // Unicode のコードポイントを表す

float32 float64

complex64 complex128

配列・スライス

配列は固定長。スライスは可変長。

a := [...]int{1, 2, 3} // 配列

s1 := []int{1, 2, 3} // スライス
s2 := []int{5, 6, 7}

// 構造体のスライス
ss := []struct {
    i int
    b bool
}{
    {2, true},
    {3, false},
    {5, true},
    {7, true},
    {11, false},
    {13, true},
}

// スライスの結合
s1 = append(s1, 4)
s1 = append(s1, s2...) // スライス同士の結合では "..." が必要

“Slicing"というテクニックで配列をスライスに変換できる。

a := [5]byte{'a', 'b', 'c', 'd', 'e'}
s := a[:] // aを参照するスライス

参考:

多次元配列・スライス

Examples:

// 二次元スライスを作成
matrix := [][]float64{{0, 0}, {0, 1}, {1, 0}, {1, 1}}

// 上と等価
matrix := make([][]float64, 4)
matrix[0] = []float64{0, 0}
matrix[1] = []float64{0, 1}
matrix[2] = []float64{1, 0}
matrix[3] = []float64{1, 1}

fmt.Println(matrix) //=> [[0 0] [0 1] [1 0] [1 1]]

参考:

map

https://golang.org/ref/spec#Map_types

初期値はnilで、データを入れようとするとパニックが起こるので、事前に割当てが必要。

// NG
var ages map[string]int
ages["carol"] = 21

// OK
ages := map[string]int{"carol": 21}

// OK
var ages map[string]int
ages = make(map[string]int)
ages["carol"] = 21

// OK
ages := make(map[string]int)
ages["carol"] = 21

for name, age := range ages {
    fmt.Printf("%s is %d years old.\n", name, age)
}

Tips:

  • mapの要素数は len(mapVal) でわかる

参考:

要素取得時のヒット検査

age, ok := ages["bob"]
if ok {
    // hit
} else {
    // miss
}

mapのマージ

逆引きGolang (マップ)より。
愚直に書く感じか。

func merge(m1, m2 map[string]string) map[string]string {
    merged := map[string]string{}

    for k, v := range m1 {
        merged[k] = v
    }
    for k, v := range m2 {
        merged[k] = v
    }
    return merged
}

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

mapのネスト

割と直感的に書ける。
宣言した時点では子要素のmapもnilなので、使う前に初期化が必要。

Example:

var nested = map[string]map[string]int{}
nested["x"] = make(map[string]int)
nested["x"]["y"] = 1

参考:

構造体

https://golang.org/ref/spec#Struct_types

Examples:

type Vertex struct {
	X int
	Y int
}

v := Vertex{}
v.X = 5

p := &v // ポインタ
p.Y = 1e9 // ポインタでも . でメンバ変数にアクセスできる
fmt.Println(v) //=> {5 1000000000}

初期化

構造体の初期化方法を示すサンプルコード:

// 例
type Foo struct {
    Name string
    Age  int
}

// (1)
f := Foo{}
f.Name = "foo"
f.Age  = 5

// (2)
f := Foo{"foo", 5} // 全てのフィールドの指定が必要

// (3)
f := Foo{Age: 5, Name: "foo"} // 任意フィールドの省略が可能。順番も入れ替え可能

もし構造体に初期値を設定したい場合、コンストラクタ的な専用の関数を作る必要があるっぽい。

参考:

タグ

構造体の定義内でメンバ変数に任意の文字列でタグを付けることができる。

Examples:

struct {
    microsec  uint64 `protobuf:"1"`
    serverIP6 uint64 `protobuf:"2"`
}

type Server struct {
    Host      string `json:"host" toml:"host"`
    IPAddress string `json:"ip_address" toml:"ip_address"`
    Port      int    `json:"port" toml:"port"`
    Note      string `json:"note" toml:"note"`
}

Tips:

  • ホワイトスペースで区切って複数設定できる
  • reflectで参照できるが、ライブラリから使われることが多い
    • バリデータ、(デ)シリアライザなど

参考:

インタフェース

https://golang.org/ref/spec#Interface_types

インタフェース型はinterfaceと呼ばれるメソッドの組を持つ。
インタフェース型の値は、メソッドの組と併せて任意の型の値を保持できる。 いわばインタフェースのスーパーセットであり、インタフェースの「実装」と呼ばれる。

初期化されてないインタフェース型の値は nil

Examples:

type Reader interface {
	Read(p []byte) (n int, err error)
	Close() error
}

type Writer interface {
	Write(p []byte) (n int, err error)
	Close() error
}

入門ガイド:

埋め込み

interfaceを別のinterfaceに埋め込むことができる。
埋め込まれたinterfaceはメソッド集合のユニオンを持つinterfaceとなる。

// ReadWriter's methods are Read, Write, and Close.
type ReadWriter interface {
	Reader  // includes methods of Reader in ReadWriter's method set
	Writer  // includes methods of Writer in ReadWriter's method set
}

このとき、同名のメソッドは型が同じでないとエラーになる。

Type assertions

インタフェース型の値 x と型 T があるとき、

x.(T)

は、 xnil でなく、型 T であることをアサートする。
この形式を「type assertion」という。

上のtype assertionが成り立つとき:

  • T がインタフェース型でないなら、 x の型は T に等しい
  • T がインタフェース型なら、 xT を実装している
  • 式の値は T 型になる

Examples:

var x interface{} = 7          // x has dynamic type int and value 7
i := x.(int)                   // i has type int and value 7

type I interface { m() }

func f(y I) {
	s := y.(string)        // illegal: string does not implement I (missing method m)
	r := y.(io.Reader)     // r has type io.Reader and the dynamic type of y must implement both I and io.Reader
	
}

type assertionが失敗するとrun-time panicが起こる。
が、panicを発生させない代入のやり方がある。

Examples:

v, ok = x.(T)
v, ok := x.(T)
var v, ok = x.(T)
var v, ok T1 = x.(T)

この構文で、 ok はtype assertionの成功時に true となる。
失敗時には false となり、 vT 型のゼロ値となる。

入門ガイド:

型変換

Examples:

var i int = 42
var f float64 = float64(i)
var u uint = uint(f)

// より縮めて下のように書ける
i := 42
f := float64(i)
u := uint(f)

型宣言

https://golang.org/ref/spec#Type_declarations

基底型に別名をつけることができる。

Examples:

// 組み込み型を基にする
type MyInt int
// 他 パッケージ 型を基にする
type MyWriter io.Writer
// 型リテラルを基にする
type Person struct {
    Name string
}

型エイリアス

型の別名を定義できる。

Examples:

type Applicant = http.Client

参考:

ポインタ

https://golang.org/ref/spec#Pointer_types

  • *p はポインタ p の指す変数の値を表す
  • &vv のポインタを表す

Examples:

i, j := 42, 2701
var p1 *int  // declare a pointer

p1 = &i          // point to i
fmt.Println(*p1) // read i through the pointer
*p1 = 21         // set i through the pointer
fmt.Println(i)   // see the new value of i

p2 := &j         // point to j
*p2 = *p2 / 37   // divide j through the pointer
fmt.Println(j)   // see the new value of j

入門ガイド:

関連項目