むかしのはなし
あれは僕が子供のころの話です。僕は昔、Goツアーという2週間ほどのツアーに参加していたことがありました。Goツアーというのは、行く先不明の深夜バスに乗って到着した場所で……。
という作り話はどうでもいいですね。
Let's Go Golang
最近僕が響きだけで触っているプログラミング言語のGoですが、サンプルプログラムから雰囲気だけで動かしていることに気づいてしまいました。まあ、一人で何かやる分には何も問題ないのですけど一々基本動作を調べながらプログラムを作るのは時間がかかるので、初心に振り返って最初から学びなおすことにしました。
Go言語の環境が入っていれば以下のコマンドで楽しいお勉強環境を実行できるそうです。
go tool tour
こんな感じに。
$ 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万字近い文章を投稿してしまいましたよ。
次回パートはいつになるかわかりませんが、残りパートもやっていきたいね。