A Tour of goが長くてどこまでやったかわからなくなるので自分用まとめ

  • パッケージ名はインポートパスの最後の要素と同じの名前

  • goのメソッド名は最初の文字が大文字で始まる場合にpublic扱いで、それ以外はprivate(Exported names)

  • 関数の引数は、変数名の後ろに型名を書く(Functions)

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

  • 関数の2つ以上の引数が同じ型である場合は、最後の型を残して省略出来る(Functions)

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

  • 関数は複数の戻り値を返す事が出来る(Functions)

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

    func main() {
    a, b := swap(“hello”, “world”)
    }

  • 返り値となる変数に名前をつけることができる。型を書くとI/Oが1行にまとまって見やすそう(Named return values)

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

  • var宣言で型は省略出来る(Variables)

    var c, python, java = true, false, “no!”

  • importと同様に、まとめて宣言可能

    var (
    ToBe bool = false
    MaxInt uint64 = 1<<64 - 1
    z complex128 = cmplx.Sqrt(-5 + 12i)
    )

  • var宣言のかわりに、:=を使う事もできる(Variables)

    c, python, java := true, false, “no!”

Go言語の基本型

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // uint8 の別名

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

float32 float64

complex64 complex128

Goの型変換(Type conversions)

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

fmt.Printf("%T %T %T",i, f, u) // int float64 uint

定数(Constants)

const World = "世界"
fmt.Println("Hello", World) // Hello 世界

for

// 基本
sum := 0
for i := 0; i < 10; i++ {
	sum += i
}

// 条件式以外は省略可(条件式を省略すれば無限ループになる)
sum := 1
for ; sum < 1000; {
	sum += sum
}

// Goでのwhileはforで書ける
sum := 1
for ; sum < 1000; {
	sum += sum
}

if

func pow(x, n, lim float64) float64 {
	// ifの条件式の前には簡単なステートメントを書ける
	if v := math.Pow(x, n); v < lim {
		return v
	}
	return lim
	// return v		// ただし、if-elseのスコープ外では無効(これはundefined: v になる)
}

func main() {
	fmt.Println(
		pow(3, 2, 10),
		pow(3, 3, 20),
	)
}

switch

breakは書かなくても自動でされる。代わりにbreakしたくない場合は、fallthroughを書く

条件文のないswitchは、if-then-else構造をシンプルに表現出来る

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

defer

defer へ渡した関数の実行を、呼び出し元の関数の終わり(returnする)まで遅延させる

defer へ渡した関数は LIFO(last-in-first-out) の順番で実行される

func main() {
	defer fmt.Println("world")

	var lang = "golang"

	defer fmt.Println(lang)

	lang = "ruby"

	fmt.Println("hello")	// hello golang world と出力される
}

Pointers

func main() {
	i, j := 42, 2701

	p := &i
	fmt.Println(*p) // 42
	*p = 21
	fmt.Println(i)  // 21

	p = &j
	*p = *p / 37
	fmt.Println(j)	// 73
}

Structs(構造体)

Structのフィールドには、ドット( . )でアクセスする

type Vertex struct {
	X int
	Y int
}

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

もしくはポインタでアクセス

type Vertex struct {
	X int
	Y int
}

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

Struct Literals

読んでて使い所がよくわからなかったけどのちほど調べる

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
)

func main() {
	fmt.Println(v1, p, v2, v3)	// {1 2} &{1 2} {1 0} {0 0}
}

Arrays

func main() {
	var a [2]string
	a[0] = "Hello"
	a[1] = "World"
	fmt.Println(a[0], a[1])		// Hello World
	fmt.Println(a)				// [Hello World]
}

Slices

func main() {
	s := []int{2, 3, 5, 7, 11, 13}
	fmt.Println("s ==", s)		// s == [2 3 5 7 11 13]

	for i := 0; i < len(s); i++ {
		fmt.Printf("s[%d] == %d\n", i, s[i])
	}
}

Slices of Slices

スライスには任意の型を収めることができ、他のスライスを入れることもできる

func main() {
	// Create a tic-tac-toe board.
	game := [][]string{
		[]string{"_", "_", "_"},
		[]string{"_", "_", "_"},
		[]string{"_", "_", "_"},
	}

	// The players take turns.
	game[0][0] = "X"
	game[2][2] = "O"
	game[2][0] = "X"
	game[1][0] = "O"
	game[0][2] = "X"

	printBoard(game)
}

func printBoard(s [][]string) {
	for i := 0; i < len(s); i++ {
		fmt.Printf("%s\n", strings.Join(s[i], " "))
	}
}

/*
	X _ X
	O _ _
	X _ O
*/

Slicing slices

s[lo:hi]	// lo から hi-1 までの要素のスライスを返す
s[lo:lo]	// 空のスライスとなる
s[lo:lo+1]	// 1つの要素を持つスライスとなる

s := []int{2, 3, 5, 7, 11, 13}
fmt.Println("s ==", s)
fmt.Println("s[1:4] ==", s[4:4])			// []

// missing low index implies 0
fmt.Println("s[:3] ==", s[:3])				// [2 3 5]

// missing high index implies len(s)
fmt.Println("s[4:] ==", s[4:])				// [11 13]

Making slices

// 長さ5のスライスを生成
a := make([]int, 5)		// [0 0 0 0 0]

// 3番目の引数に、スライスの容量を指定出来る
b := make([]int, 0, 5)	// []

Nil slices

スライスのゼロ値はnil

var z []int
fmt.Println(z, len(z), cap(z))
if z == nil {
	fmt.Println("nil!")
}

Adding elements to a slice

スライスへ新しい要素を追加するには、appendを使用。

var a []int
fmt.Printf("%s", a);

var a []int
fmt.Printf("%d\n",a)		// []
a = append(a, 0)
fmt.Printf("%d\n",a)		// [0]
a = append(a, 2, 3, 4)
fmt.Printf("%d\n",a)		// [0 2 3 4]

Range

rangeは反復毎に2つの変数を返す。1つ目の変数はインデックスで、2つ目の変数は値。(foreach的な感じ)

変数の部分に_(アンダーバー)を指定する事で、値は捨てる事が出来る

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

for i, v := range pow {
	fmt.Printf("2[%d] = %d\n", i, v)
}

for _, v := range pow {
	fmt.Printf("2[%d] = %d\n", i, v)	// iは捨てているのでエラーになる。(vだけならばエラーにならない)
}

Maps

map[(keyの型)](valueの型)という感じで書く

mapはmakeで作成する必要がある

type Vertex struct {
	Lat, Long float64
}

var m map[string]Vertex

m = make(map[string]Vertex)
m["Bell Labs"] = Vertex{
	40.68433, -74.39967,
}
fmt.Println(m["Bell Labs"])

Map literals

type Vertex struct {
	Lat, Long float64
}

var m = map[string]Vertex{
	"Bell Labs": Vertex{
		40.68433, -74.39967,
	},
	"Google": Vertex{
		37.42202, -122.08408,
	},
}

fmt.Println(m)	// map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]

mapに渡すトップレベルの型が単純な型である場合、型は省略できる

var m = map[string]Vertex{
	"Bell Labs": {40.68433, -74.39967},
	"Google":    {37.42202, -122.08408},
}

Mutating Maps

// 要素の挿入・更新
m[key] = elem

// 要素の取得
elem = m[key]

// 要素の削除
delete(m, key)

// キーに対する要素が存在するかどうか、2つ目の値で確認出来る(変数okはboolで存在すればtrue)
// mapにkeyが存在しない場合、elemはmapの要素の型のゼロ値になる
elem, ok = m[key]

// elemとokが未宣言であれば、 := で省略できる
elem, ok := m[key]

Function closures

func adder() func(int) int {
	sum := 0
	fmt.Println("adder")
	return func(x int) int {
		sum += x
		return sum
	}
}

func main() {
	pos := adder()
	for i := 0; i < 10; i++ {
		fmt.Println(pos(i))
	}
}

// adder
// 0
// 1
// 3
// 6
// 10

Methods

Goにはclassのしくみはないが、struct型にMethodを定義出来る((v *Vertex)の部分を「レシーバ」と言う)

type Vertex struct {
	X, Y float64
}

func (v *Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
	v := &Vertex{3, 4}
	fmt.Println(v.Abs())	// 5
}

Interfaces

interface型は、Methodの集まりで定義。

type Abser interface {
	Abs() float64
}

func main() {
	var a Abser
	f := MyFloat(-math.Sqrt2)
	v := Vertex{3, 4}

	a = f  // a MyFloat implements Abser
	a = &v // a *Vertex implements Abser

	// In the following line, v is a Vertex (not *Vertex)
	// and does NOT implement Abser.
	a = v		/* Absは、Vertexではなく*Vertexの定義なので、ここでエラーになる */

	fmt.Println(a.Abs())
}

type MyFloat float64

func (f MyFloat) Abs() float64 {
	if f < 0 {
		return float64(-f)
	}
	return float64(f)
}

type Vertex struct {
	X, Y float64
}

func (v *Vertex) Abs() float64 {	// ←レシーバを*VertexからVertexに変更するとエラーがでなくなる
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

Stringers

よく使われているinterfaceの1つに、fmtパッケージに定義されているStringerがある

type Stringer interface {
	String() string
}

Stringer インタフェースは、stringとして表現することができる型です。 fmt パッケージ(と、多くのパッケージ)では、変数を文字列で出力するためにこのインタフェースがあることを確認します。

package main

import "fmt"

// 構造体
type Person struct {
	Name string
	Age  int
}

// 構造体にメソッドを実装
func (p Person) String() string {
	return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}

func main() {
	a := Person{"Arthur Dent", 42}
	z := Person{"Zaphod Beeblebrox", 9001}

	fmt.Println(a, z)		// Arthur Dent (42 years) Zaphod Beeblebrox (9001 years)
}

Errors

Go言語では例外という概念はなく、error型という変数が用意されている

package main

import (
	"fmt"
	"time"
)

type MyError struct {
	When time.Time
	What string
}

func (e *MyError) Error() string {
	return fmt.Sprintf("at %v, %s",
		e.When, e.What)
}

func run() error {
	return &MyError{
		time.Now(),
		"it didn't work",
	}
}

func main() {
	if err := run(); err != nil {
		fmt.Println(err)		// at 2009-11-10 23:00:00 +0000 UTC, it didn't work
	}
}

その他

ここからは、実際に触ってみる途上で試してみた事とかのメモ

  • importはディレクトリしか指定出来ない(ファイル単体をimportしようとするとエラーになる)