Go 入門

Table of Contents

1 公式チュートリアル

2 規格まとめ

2.1 特徴

  • 文の区切りに ; を使用しない
  • 型の宣言はシンボル名の後
  • 多値返却
  • 型推論に対応(ただし、専用の宣言方法が必要)
  • 変数のデフォルトは mutable
  • for 文などは、必ずブロックを持つ。

2.2 関数

func add(x int, y int) int {
	return x + y
}

同じ型の引数が複数ある場合、最後以外の型宣言を省略できる。

func add(x, y int) int {
	return x + y
}

多値返却をサポートする。 多値返却は () で括る。 これはタプルではない。

func swap(x, y string) (string, string) {
	return y, x
}

戻り値を関数宣言時に指定できる。 次の場合、宣言時に x, y を戻り値に指定し、関数本体では return だけを書いている。

func split(sum int) (x, y int) {
	x = sum * 4 / 9
	y = sum - x
	return
}

2.3 変数

var で宣言する。 初期化していない場合の値は??? 型によって決っている?

var c, python, java bool

func main() {
	var i int
	fmt.Println(i, c, python, java)
}

初期化。

var i, j int = 1, 2

func main() {
	var c, python, java = true, false, "no!"
	fmt.Println(i, j, c, python, java)
}

:= を使って型推論。 ただし、これは関数内部でのみ有効。

func main() {
	var i, j int = 1, 2
	k := 3
	c, python, java := true, false, "no!"

	fmt.Println(i, j, k, c, python, java)
}

2.4

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // uint8 の別名

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

float32 float64

complex64 complex128

int/uint のサイズは、処理系によって異なる。 サイズを限定する場合以外は int/uint の使用を推奨。

2.4.1 ゼロ値

初期値を与えない変数の初期値。

数値型(int,floatなど): 0
bool型: false
string型: "" (空文字列( empty string ))

2.4.2 型変換

ある値 v を、型 T に変換する場合、 T(v) で変換する。

i := 42
f := float64(i)  // <- 42 を float64 に変換
u := uint(f)     // <- 42 を uint に変換

2.4.3 Constant

定数は Constant で変数を宣言する。 定数なので、当然初期値を設定する。 この初期値を使って型推論も行なうので、型宣言は不要。 なお、変数の型推論は関数内だけで有効だが、 Constant は関数外でも有効。

const Pi = 3.14

func main() {
	const World = "世界"
	fmt.Println("Hello", World)
	fmt.Println("Happy", Pi, "Day")

	const Truth = true
	fmt.Println("Go rules?", Truth)
}
  1. 数値の Constant

    数値型の範囲(64bit)では表現できない値も、 Constant であれば表現できる。

    const (
    	// Create a huge number by shifting a 1 bit left 100 places.
    	// In other words, the binary number that is 1 followed by 100 zeroes.
    	Big = 1 << 100
    	// Shift it right again 99 places, so we end up with 1<<1, or 2.
    	Small = Big >> 99
    )
    
    func needInt(x int) int { return x*10 + 1 }
    func needFloat(x float64) float64 {
    	return x * 0.1
    }
    
    func main() {
    	fmt.Println(needInt(Small))
    	fmt.Println(needFloat(Small))
    	fmt.Println(needFloat(Big))
    }
    

2.5 for

  • ほぼ C と同じ。
  • スコープは for ループで閉じる。
func main() {
	sum := 0
	for i := 0; i < 10; i++ {
		sum += i
	}
	fmt.Println(sum)
}

For の 3 つのループ制御ステートメントはそれぞれ省略可能。 これにより、 while/無限ループを表現する。 For で while と等価な表現ができるため、 go は while をサポートしない。

while と等価の for。

func main() {
	sum := 1
	for sum < 1000 {
		sum += sum
	}
	fmt.Println(sum)
}

無限ループの for。

func main() {
	for {
	}
}

2.6 if

  • () が無い
  • {} が必須
  • 条件式の前に文を書ける。
    • ここで宣言した変数は if と else のスコープ。
func pow(x, n, lim float64) float64 {
	if v := math.Pow(x, n); v < lim {
		return v
	}
	return lim
}

2.7 switch

  • switch は if/else のシンタックスシュガー。
  • 条件文の前の文も書ける。
  • シンタックスシュガーなので、 case の各式は上から順に評価される。
  • C のような fall-through はない。
    • break はなくても、一致した case/default を実行したら終わる。
func main() {
	fmt.Print("Go runs on ")
	switch os := runtime.GOOS; os {
	case "darwin":
		fmt.Println("OS X.")
	case "linux":
		fmt.Println("Linux.")
	default:
		// freebsd, openbsd,
		// plan9, windows...
		fmt.Printf("%s.", os)
	}
}

2.7.1 switch の値を省略

switch の値を省略すると switch true と同義。

func main() {
	t := time.Now()
	switch {
	case t.Hour() < 12:
		fmt.Println("Good morning!")
	case t.Hour() < 17:
		fmt.Println("Good afternoon.")
	default:
		fmt.Println("Good evening.")
	}
}

2.8 defer

  • 関数コールを呼び出し元関数終了時に実行するように予約する。
  • 関数コールの引数に与えている式は、 defer 評価時に実行される。

次は hello hoge ではなく、hello world が表示される。

func main() {
	txt := "world"
	defer fmt.Println( txt )
	txt = "hoge"

	fmt.Println("hello")
}

defer の予約は、スタックに Push される。

func main() {
	fmt.Println("counting")

	for i := 0; i < 10; i++ {
		defer fmt.Println(i)
	}

	fmt.Println("done")
}

2.9 ポインタ

  • 値を格納しているポインタを扱える。
  • ただし、ポインタの演算はできない。
  • C++ の参照と考えれば良い。
  • ゼロ値は nil。
  • 演算子は C と同じ。 &val でポインタ取得。 *val でポインタが格納する値を取得。
func main() {
	i, j := 42, 2701

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

	p = &j         // point to j
	*p = *p / 37   // divide j through the pointer
	fmt.Println(j) // see the new value of j -- 73
}

2.10 構造体

  • メンバアクセスは C と同じで . を使用する。
  • ただし、ポインタ経由のアクセス方法が異なる
    • 時に -> は使用せず、 . を使用する。
    • (*p).val のようにも書けるが、 p.val と同義。
  • Println は、構造体のデータを出力可能
  • 構造体のポインタを Println すると、 & を付加した
type Vertex struct {
	X int
	Y int
}

func main() {
	v := Vertex{1, 2}
	p := &v
	p.X = 1e9
	fmt.Println(v)
}

2.10.1 構造体リテラル

  • 構造体の初期化データ。
  • メンバの初期化は宣言順に処理される。
  • 初期値を与えないメンバは、ゼロ値で初期化される。
  • 構造体リテラルのポインタも取れる。
type Vertex struct {
	X, Y int
}

var (
	v1 = Vertex{1, 2}  // has type Vertex
	v2 = Vertex{X: 1}  // Y:0 is implicit
	v3 = Vertex{}      // X:0 and Y:0
	p  = &Vertex{1, 2} // has type *Vertex
)

2.11 配列

  • 要素数固定のシーケンス。
  • 要素数は、宣言時に指定する。
  • 配列は [N]T として宣言する。ここで N は要素数、T は型。
func main() {
	var a [2]string
	a[0] = "Hello"
	a[1] = "World"
	fmt.Println(a[0], a[1])
	fmt.Println(a)

	primes := [6]int{2, 3, 5, 7, 11, 13}
	fmt.Println(primes)
}

2.11.1 スライス

  • スライスは、配列の一部を参照する。
  • スライスの型は []T として宣言する。要は配列の N がない形になる。
func main() {
	primes := [6]int{2, 3, 5, 7, 11, 13}

	var s []int = primes[1:4]
	fmt.Println(s)
}
  • 上記の primes[1:4] がスライス
  • ここで primes[1:4] は、 {3,5,7} を示す。 つまり 1 から (4-1) 番目まで。
  • スライスは参照なので、スライスの要素を変更すると、参照元の値も変更になる。
  • 次の場合、スライス s[1] = 0 しているが、これによって、 primes[ 2 ] が変わる。
func main() {
	primes := [6]int{2, 3, 5, 7, 11, 13}

	var s []int = primes[1:4]
	fmt.Println(s)
	s[1] = 0;
	fmt.Println( primes )  // [2 3 0 7 11 13]
}
  1. スライスの範囲
    • スライスの範囲は、省略できる。
    • 省略した場合、最小、あるいは最大になる。
    • 次の s1 〜 s4 は同じ範囲を示す。
    func main() {
    	primes := [6]int{2, 3, 5, 7, 11, 13}
    
    	s1 := primes[ 0: 6 ]
    	s2 := primes[ : 6 ]
    	s3 := primes[ 0: ]
    	s4 := primes[ : ]
    }
    
  2. スライスの len と cap
    • len は、スライスの要素数
    • cap は、次の式から得られる
    スライスが参照する元の配列の要素数 - スライスが先頭が参照する元の配列インデックス
    

2.12 パッケージ

  • 公開シンボルは大文字で始める。

2.13 import

パッケージをインポートする。

import (
  "fmt"
  "math"
)
import "fmt"
import "math"

Author: ifritJP

Created: 2020-04-07

Validate