Go言語初心者が学んだ基礎的な文法まとめ

## Go言語の型の種類

こんにちは。僕もGoを勉強し始めることになりました。
学んだ文法をまとめたいと思います。

## 変数
### 型を宣言して使う
```go
//型を宣言する
var str string
str = "hello"
fmt.Println(str)//=>hello
fmt.Println(reflect.TypeOf(str))//=>string
```
### 型推論
```go
//型は推論される
var str = "hello"
fmt.Println(str) //=>hello
fmt.Println(reflect.TypeOf(str)) //=>string
```

### varを省略する
```go
//変数宣言と初期化を行う場合に、var と型宣言を省略して「:=」演算子を用いることができる。
str := "hello"
fmt.Println(str)//=>hello
fmt.Println(reflect.TypeOf(str))//=>string
```

## 型の種類
主にこんな感じ。

```go
int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex64 complex128
bool byte
string rune
```

## 型の変換
型の変換には"strconv"を使用する。
### 文字列から数値に変換する
```go
import (
    "fmt"
    "strconv"
    "reflect"
)

func main() {
    var i int
    i, _ = strconv.Atoi("100")
    fmt.Println(i) //=>100
    fmt.Println(reflect.TypeOf(i)) //=>int

}
```
### 数値から文字列に変換する
```go
import (
    "fmt"
    "strconv"
    "reflect"
)

func main() {
fmt.Println(strconv.Itoa(100)) //=>100
fmt.Println(reflect.TypeOf(strconv.Itoa(100))) //=>string
}
```

## interface型
全ての型と互換性を持っているinterface{}型

```go
var obj interface{}

obj = 123                                                              // int
obj = "str"                                                            // string
obj = []string{"linux", "windows", "android"}                          // slice
obj = make(chan string)                                                // channel
obj = func(val int) string { return fmt.Sprintf("number is %d", val) } // function
```
[Go言語 - 空インターフェースと型アサーション](http://blog.y-yuki.net/entry/2017/05/08/000000)

## ポインタ型
```go
func callByValue(i int) {
    i = 20 // 値を上書きする
}

func callByRef(i *int) {
    *i = 20 // 参照先を上書きする
}

func main() {
    var i int = 10
    callByValue(i) // 値を渡す
    fmt.Println(i) // 10
    callByRef(&i) // アドレスを渡す
    fmt.Println(i) // 20
}
```
[はじめてのGo―シンプルな言語仕様，型システム，並行処理](http://gihyo.jp/dev/feature/01/go_4beginners/0002?page=5#secc)

ポインタ型とそうではない型の違いは、構造体の部分で書きます。

## 型の確認
型の確認には、reflectを使う。

```go
package main

import (
    "fmt"
    "reflect"
)

func main() {
    fmt.Println(reflect.TypeOf(1))   //=>int
    fmt.Println(reflect.TypeOf("test"))   //=>string
    fmt.Println(reflect.TypeOf([]string{"a", "b", "c"}))  //=>[]string
}
```

## 配列
型とサイズを決めて配列を宣言。

```go
var arr [5]int
//5つのものが入る配列arrを宣言
```

```go
//6以上入るとエラー。
var arr [5]int
arr[5] = 5
fmt.Println(arr) //=>invalid array index 5 (out of bounds for 5-element array)
```
宣言した数以上のものを入れることができない。
柔軟に対応するためには、どうするか=>sliceを使う。

## slice
配列は入れることのできる数が決まっているが、sliceは決まっていない。可変長である。
### sliceの定義方法
```go
a:=[]T{}
a:=make([]T,len)
```
### sliceの使い方
```go
fruits := []string{"apple", "orange", "lemon"}
fmt.Println(fruits) // => [apple orange lemon]
fruits = append(fruits, "peach")
//追加の際には、appendを使う。
fmt.Println(fruits) //=>[apple orange lemon peach]
//peachが追加された。
```
## map(連想配列)
Golangではハッシュ（連想配列)のことをmapと呼ぶ。

```go
package main

import (
    "fmt"
)

func main() {
    m := map[string]int{"japanese": 68, "english": 70, "math": 90}
    fmt.Println(m) //=>map[japanese:68 english:70 math:90]
    fmt.Println(m["japanese"]) //=>68
    //mapからキーの値を取り出す
    m["science"] = 100
    //要素を追加する
    fmt.Println(m) //=>map[japanese:68 english:70 math:90 science:100]
}
```

## 構造体
### struct定義
structを使ってそのフィールドが持つ値を決定することができる。

```go
type Animal struct {
    Name string
    Age  int
}
```
クラスのようなもの。
### structを初期化する
初期化の方法にもいくつかあるので、見ていきます。
#### newを使う
さっき作ったAnimalを初期化します。初期化したanimalに値を入れます。

```go
package main

import "fmt"

type Animal struct {
    Name string
    Age  int
}

func main() {
    animal := new(Animal)//:= でポインタ型
    animal.Name = "Tanaka"//NameにTanakaを代入
    animal.Age = 10//Ageに10を代入

    fmt.Println(animal)
    //=>&{Tanaka 10}
}
```
ポインタ型でTanakaと10というものが返ってきます。

#### ポインタ型で初期化する
```go
package main

import "fmt"

type Animal struct {
    Name string
    Age  int
}

func main() {
    animal := &Animal{
        Name: "Tanaka",
        Age: 10,
    }
    fmt.Println(animal)
    //=>&{Tanaka 10}
}
```
これでも同じ結果です。

#### そのまま初期化して使う
```go
package main

import "fmt"

type Animal struct {
    Name string
    Age  int
}

func main() {
    animal := Animal{
        Name: "Tanaka",
        Age: 10,
    }
    fmt.Println(animal)
    //=>{Tanaka 10}
}
```
今回はポインタ型ではなく、そのまま出力されました。

## 構造体の初期化方法で何が違うのか
これは一体何が違うのでしょう。


以下の記事に違いが書かれていました。引数として使った場合などに変化が見られるそうです。
https://qiita.com/kmtr/items/1e7caf92aa8bb587906d

試してみます。

```go
package main

import "fmt"

type Animal struct {
    Name string
    Age  int
}

func changeAge1(animal1 Animal, age int) {
    animal1.Age = age
    fmt.Printf("%p\n", &animal1)
}

func changeAge2(animal2 *Animal, age int) {
    animal2.Age = age
    fmt.Printf("%p\n", animal2)
}

func main() {

    animal1 := Animal{
        Name: "Tanaka",
        Age: 10,
    }
    fmt.Printf("%p\n", &animal1)
    changeAge1(animal1, 100)

    animal2 := &Animal{
        Name: "Tanaka",
        Age: 10,
    }

    fmt.Printf("%p\n", animal2)
    changeAge2(animal2, 100)
}
```
結果

```
0xc42000a060
0xc42000a080
0xc42000a0a0
0xc42000a0a0
```
なるほど、確かに以下のように構造体を初期化した場合は、引数として使うと、構造体の値を変更した際にポインタが変わってしまうようです。

```go
    animal1 := Animal{
        Name: "Tanaka",
        Age: 10,
    }
```

構造体の初期化方法というよりポインタの扱い方な気がします。
[Goのポインタ]
(http://cuto.unirita.co.jp/gostudy/post/pointer/#ポインタ渡しと値渡し:ffdeb3f7885f136b06b51e3b151b807e)が参考になります。

## for文
```go
package main

import "fmt"

func main() {
	sum := 0
	for i := 0; i < 10; i++ {
		sum += i
	}
	fmt.Println(sum)
}
```
## if文
```go
package main

import (
	"fmt"
	"math"
)

func sqrt(x float64) string {
	if x < 0 {
		return sqrt(-x) + "i"
	}
	return fmt.Sprint(math.Sqrt(x))
}

func main() {
	fmt.Println(sqrt(2), sqrt(-4))
}
```
## switch文
```go
package main

import (
	"fmt"
	"runtime"
)

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)
	}
}
```
## 終わりに
Go言語触ってみましたが、正直まだまだ見えてきません。
いつか見えてくる日がくるのだろうか。その時を待ちたいと思う。