コミュ障だから明日が僕らをよんだって返事もろくにしなかった

何かを創る人に憧れたからブログをはじめたんだと思うよ

Goツアーのおもいで Part 1

むかしのはなし

あれは僕が子供のころの話です。僕は昔、Goツアーという2週間ほどのツアーに参加していたことがありました。Goツアーというのは、行く先不明の深夜バスに乗って到着した場所で……。

という作り話はどうでもいいですね。

Let's Go Golang

最近僕が響きだけで触っているプログラミング言語のGoですが、サンプルプログラムから雰囲気だけで動かしていることに気づいてしまいました。まあ、一人で何かやる分には何も問題ないのですけど一々基本動作を調べながらプログラムを作るのは時間がかかるので、初心に振り返って最初から学びなおすことにしました。

Go言語の環境が入っていれば以下のコマンドで楽しいお勉強環境を実行できるそうです。

go tool tour

こんな感じに。
f:id:andron:20180104163545p:plain

$ go tool tour -h
Usage of tour.exe:
  -http string
        host:port to listen on (default "127.0.0.1:3999")
  -openbrowser
        open browser automatically (default true)

そのまま利用すると3999番になるらしく。僕はここで小一時間つまづきました。避けたい場合はオプションを使いましょう。

Go Go Golang

そうしたわけでざっくりと見ていきます。

1. Hello World
まずはよくあるハロワ。fmtが出力用のおまじない。

package main
import "fmt"
func main() {
	fmt.Println("Hello, 世界") // Hello, 世界
}
基礎編

◆ 基本構成
1. Package
Goのプログラムはパッケージで構成される。
2. Import
Importでパッケージをインポートできるそうです。( )でまとめることもできるそうで。

package main
import (
	"fmt"
	"math/rand"
)
func main() {
	fmt.Println("ランダムな数値:", rand.Intn(10))
}

3. Exported names
math.Piみたいに特別なやつがあるから大文字で書きましょうみたいなはなし。

func main() {
	fmt.Println(math.Pi)
}

4. Functions
いわゆる関数。変数の後ろに型名をつけろとのことです。

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

5. Functions continued
同じ型の省略表現。上のやつを以下のように省略できるな話

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

6. Multiple results
複数の戻り値を返すそうです。C言語よりスゴイ!

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

7. Named return values
戻り値に名前を付けられる。利点はよくわからない。他言語と比べて不自由な点がいくつかあるそうなのでそれを補うために使うと思われ。

8. Variables
変数のこと。

var c, python, java bool

9. Variables with initializers
変数の初期値のこと。僕的に書き方がいまいち慣れない。

var i, j int = 1, 2

10. Short variable declarations
暗黙的な型宣言。:=でできるそうです。

11. Go言語の基本型
以下の通りだそうです。細かいことはよくわからない。

bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // uint8 の別名
rune // int32 の別名
// Unicode のコードポイントを表す
float32 float64
complex64 complex128

12. Zero values
変数に初期値がないとゼロ値になるとのことです。

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

13. Type conversions
型変換のこと。Goだと明示的変換が必要になるので重要っぽいです。

i := 42
f := float64(i)
u := uint(f)

14. Type inference
型推論なはなし。明示的にやらないと、以下のようになる仕様らしい。

右側に型を指定しない数値である場合、左側の新しい変数は右側の定数の精度に基いて int, float64, complex128 の型になります

15. Constants
定数のこと。いじれないやつ。:=の表記は禁止らしい。

const World = "世界"

16. Numeric Constants
数値定数。めちゃ細かい数値を扱うときにもconstは有効みたいな話でいいんですかね……。



◆ フロー制御
1. For
ループするやつ。Cとの違いは()が不要なこと。

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

2. For continued
初期化と後処理ステートメントの記述は任意らしい。個人的に読みにくい。

	sum := 1
	for ; sum < 1000; {
		sum += sum
	}

3. For is Go's "while"
whileっぽく書くにはセミコロンを省略して以下のようにするらしい。

	sum := 1
	for sum < 1000 {
		sum += sum
	}

4. Forever
無限ループって怖くね?ループ条件を無視すると無限ループするらしいです。

	for {
	}

5. If
条件分岐のやつ。( )は不要とのことです。

	if x < 0 {
		return 
	}

6. If with a short statement
forみたいな評価もできるとのことです。個人的に慣れてないから読み辛い。

func pow(x, n, lim float64) float64 {
	if v := math.Pow(x, n); v < lim {
		return v
	}
	return lim
}

7. If and else
elseの使い方。特に変わったことはない。

	if v := math.Pow(x, n); v < lim {
		return v
	} else {
		fmt.Printf("%g >= %g\n", v, lim)
	}

8. Exercise: Loops and Functions
突然の実習問題!!
ニュートン法を使って二乗計算を近似してみようという話。

package main
import (
	"fmt"
	"math"
)
func Sqrt(x float64) float64 {
	var z float64 = 1
	for i := 0; i < 10; i++ {
		z = z - ((z*z - x) / (2 * z))
	}
	return z
}
func main() {
		fmt.Println(Sqrt(2))           // 結果   :1.414213562373095
		fmt.Println(math.Sqrt(2)) // 比較用:1.4142135623730951
}

多分こんな感じ。結果がそれっぽく近似されたのでこれで良しとした。

9. Switch
caseの最後は必ずbreakするそうです。通したい場合はfallthroughを最後につけろとのことです。

	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)
	}

10. Switch evaluation order
switchの順序は上から下みたいな話。9にもあるように逐次breakされるのに注意だって。

11. Switch with no condition
条件をつけないとswitch trueになるとのことです。

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

12. Defer
遅延。呼出元の関数が終わるまで遅延だそうです。

	defer fmt.Println("world")
	fmt.Println("hello")
           // hello world

13. Stacking defers
複数のdeferはstackされるらしい。

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

これでカウントダウンみたいになるの面白いなって思った(小学生並みの感想)。



◆ その他いろいろ
1. Pointers
変数のメモリアドレスのこと。つまりどういうことかはよくわからない。よくわかんないけどこんな感じになる。まあ、使っているうちに覚えるからいいでしょう。

	i := 42
	p := &i         // point to i
	fmt.Println(*p) // 42
	fmt.Println(p)  // 0x******
	
	*p = 21         // set i through the pointer
	fmt.Println(i)  // 21

2. Structs
構造体のこと。フィールドの集まりともいう。つまりどういうことなのかわからない。

type Vertex struct {
	X int
	Y int
}

3. Struct Fields
structのフィールド。.を使えば行けるよみたいなこと。

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

4. Pointers to structs
ポインタを通してもいけるよってはなし。

5. Struct Literals
こうやって一部だけの表記もできるらしい。

type Vertex struct {
	X, Y int
}
var{
        v = Vertex{X: 1}  // Y:0 is implicit
}

6. Arrays
おなじみ配列。散々見てきているのに型を後ろに書く書き方に慣れない。

	var a [2]string
	a[0] = "Hello"
	a[1] = "World"

7. Slices
柔軟な方の配列、スライス。

	primes := [6]int{2, 3, 5, 7, 11, 13}
	var s []int = primes[1:4]

8. スライスは配列への参照のようなものです
らしいね(他人事)。

9. Slice literals
スライスのお作法1。

  r := []bool{true, true, false}

10. Slice defaults
スライスのお作法2。

	s := []int{2, 3, 5, 7, 11, 13}
	s = s[0:5] //[2 3 5 7 11]
	s = s[:5] //[2 3 5 7 11]
	s = s[0:] //[2 3 5 7 11]
	s = s[:] //[2 3 5 7 11]

11. Slice length and capacity
スライスの長さと容量。スライスsに対して長さlen(s)、容量cap(s)で表される。キャパの管理重要っぽいです。うまくできないと以下のようなエラーがでます。

panic: runtime error: slice bounds out of range

12. Nil slices
スライスのゼロ値はnil

13. Creating a slice with make
make関数でスライス作れるってさ。

a := make([]int, 5)  // len(a)=5
b := make([]int, 0, 5) // len(b)=0, cap(b)=5

14. Slices of slices
スライスのスライス。スライスのお作法3。
スライスは、他のスライスを含む任意の型を含むことができるらしいです。

15. Appending to a slice
スライスのお作法4。新しい要素を追加したいとき。appendを使えって。

16. Range
例えばこんな感じに、ループのときに逐次処理ができる

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
	for i, v := range pow {
		fmt.Printf("2**%d = %d\n", i, v)
	}
}

17. Range continued
代入不要のときは、以下のように_にすれば捨てられるって

       for _, value := range pow {
		fmt.Printf("%d\n", value)
	}

18. Exercise: Slices
突然の実習問題!!
スライスの問題。画像が生成されるPic関数を作ろうてき問題。

package main
import "golang.org/x/tour/pic"
func Pic(dx, dy int) [][]uint8 {
    img := make([][]uint8, dy)

    for y := 0; y < dy; y++ {
        img[y] = make([]uint8, dx)
        for x :=0; x < dx; x++ {
            img[y][x] = uint8(x^y)
        }
    }
    return img
}
func main() {
	pic.Show(Pic)
}

多分こんな感じ。実行するとビックリマンのキラシールみたいなのができる。

19. Maps
連想配列的なやつ。言語ごとに言い回し微妙に違うので何が正解かわからないやつ。
map関数を使えばいいって。

20. Map literals
マップのお作法。キーを使いなさい。

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

21. Map literals continued
これでもいける。

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

22. Mutating Maps
マップの操作方法

◆ map m の操作
要素(elem)の挿入や更新: m[key] = elem
要素の取得: elem = m[key]
要素の削除: delete(m, key)

23. Exercise: Maps
突然の実習問題!!
マップを使ってWordCount関数を完成させましょう問題。

package main
import (
	"golang.org/x/tour/wc"
	"strings"
)
func WordCount(s string) map[string]int {
	words := strings.Fields(s)
	m := make(map[string]int)
	
	for i := range words {
		m[words[i]] += 1
	}
	return m	
}
func main() {
	wc.Test(WordCount)
}

多分こんな感じ。
上手くいくとテストケースを通過して"PASS"とか出力されるようです。

24. Function values
関数も変数として扱えるよって話。

25. Function closures
Goのクロージャ

func adder() func(int) int {
	sum := 0
	return func(x int) int {
		sum += x
		return sum
	}
}
func main() {
	pos, neg := adder(), adder()
	for i := 0; i < 10; i++ {
		fmt.Println(
			pos(i),
			neg(-2*i),
		)
	}
}

26. Exercise: Fibonacci closure
突然の実習問題!!
フィボナッチ数列を作ろう問題。

package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
	f2, f1 := 0, 1
	return func() int {
		f1, f2 = f2, f1+f2
		return f1
	}
}
func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}

多分こんな感じ。

おわりに

適当に書いていればサクッと終わるだろうと思ったら結構な量になってしまった。Goツアー結構ボリュームあるね……。それと実習問題もついていると思わなかった。このせいで時間がかかってしまった。久しぶりに1万字近い文章を投稿してしまいましたよ。

次回パートはいつになるかわかりませんが、残りパートもやっていきたいね。