入門プログラミングGo(型宣言、メソッド、配列、スライス、可変長引数、map)

## 型宣言
```go
type long float64
type large float64
```

## 型変換
```go
var lg long = 333.3;
large(lg)//型変換
```

## メソッド
### オブジェクト指向のメソッド
>オブジェクト指向プログラミングは、クライアントがオブジェクト内部表現に直接アクセスする必要がないようにするために、個々のデータ構造の特性と操作を表現するためのもの

### Golangのメソッド
>Goにおいてのオブジェクトはメソッドを持つ単なる変数であり、メソッドは特定の型に関連付けられた関数。
（参考：https://qiita.com/pei0804/items/2a3010df39623fadc3c6）

## メソッドの定義方法
```go
func (レシーバー 型) 関数名 (引数) 戻り値の型 {

}
```

### 関数を変数に代入することもできる
```go
package main
import (
	"fmt"
	"math/rand"
)
type kelvin float64
func fakeSensor() kelvin {
	return kelvin(rand.Intn(151) + 150)
}
func realSensor() kelvin {
	return 0
}
func main() {
	sensor := fakeSensor
//  型推論を使用しないとき
    var sensor func() kelvin
	fmt.Println(sensor())
	sensor = realSensor
	fmt.Println(sensor())
}
```
このときの`sensor`は関数型

#### 関数型
宣言例
func(int, int) int

## クロージャ
- 関数を処理中に、その場で作る必要があるとき使用される

### クロージャの一番簡単な例
```go
package main
import "fmt"
// クロージャーの実装
func addGen2() (func() int) {
    x := 0
    return func() int {
        x++
        return x
    }
}
func main() {
    // addGen2は関数が戻り値なので変数に代入する
    add2 := addGen2()//x := 0が実行される
    fmt.Println(add2())
    fmt.Println(add2())
    fmt.Println(add2())
}
```
(参考：https://golangstart.com/go_closure/#toc3)

- `add2`を参照し続ける限り`x`は保持され続ける
- add2()は無名関数部分が実行される（）

# 配列
```go
package main
import (
	"fmt"
)
func main() {
	var planets [8]string//配列の要素数と型の宣言
	planets[0] = "水星"
	planets[1] = "金星"
	planets[2] = "地球"
	planets[3] = "火星"
	for i := 0; i < 4; i++ {
		fmt.Println(planets[i])
	}
}
```
<b>複合リテラル</b>表記👇
```go
	planets2 := [...]string{
		"水星",
		"金星",
		"地球",
		"火星",
	}
	for i := 0; i < len(planets2); i++ {
		fmt.Println(planets2[i])
	}
```

配列はDeep Copyされる
```go
	planets2 := [...]string{
		"水星",
		"金星",
		"地球",
		"火星",
	}
    planets3 := planets2//参照は共有されない
```
# スライス
```go
	planets := [...]string{
		"水",
		"金",
		"地",
		"火",
		"木",
		"土",
		"天",
		"海",
	}
	terrestrial := planets[0:4]
	gasGiants := planets[4:6]
	iceGiants := planets[6:8]
	fmt.Println(terrestrial, gasGiants, iceGiants)
	iceGiantsM2 := planets[6:8]
	iceGiantsM2[1] = "Poseidon"
    planets3 := []string{//something}
	fmt.Println(iceGiantsM2)
```
- 配列が直接使用されることはほとんどない。スライスが使用される
- いきなりスライスを作ることも可能
    ```go
    samples := []string{"a", "b", "c", "d", "e", }
    ```
裏では基底配列が存在し、5つの要素を持つ配列が宣言され、その全部の要素を見るスライスが作られる

- スライスに要素を追加する

dwarfs := []string{"Ceres", ""}

# make 関数
スライスの事前割り当て
👇の例ではappendで容量が足りなくて臨時でコピーと割り当てをする必要がない
```go
dwarfs := make([]string, 0, 10)
dwarfs = append(dwarfs, "Ceres", "Pluto", "Haumea", "Makemake", "Eris")
```

# 可変長引数
```go
package main
import (
	"fmt"
)
func terraform(prefix string, worlds ...string) []string {
    // ...は可変長引数を使用する合図
	newWorlds := make([]string, len(worlds))
	for index, value := range worlds {
		newWorlds[index] = prefix + " " + value
        // rangeの第一引数は"index番号"、第二引数はindex番号に対応した配列の値
	}
	return newWorlds
}
func main() {
	twoWorlds := terraform("New", "Venus", "Mars")
	fmt.Println(twoWorlds)
}
```

# map
```go
package main
import (
	"fmt"
)
func main() {
	temperature := map[string]int{
		"Earth": 15,
		"Mars":  -65,
	}
	temp := temperature["Earth"]
	fmt.Println(temp)
	temperature["Venus"] = 455
	fmt.Println(temperature)
}
```
マップに存在しないキーをアクセスしたら、結果は値の型（int）のゼロ値になる
`map`の`value`が0のときと、`map`に`key`がないときは`,ok`構文を用いる
```go
if moon, ok := temperature["Moon"]; ok {
    // 内容
} else {
    // 内容
}
```

出現頻度を出力するプログラム
```go
package main
import (
	"fmt"
)
func main() {
	temperature := []float64{
		-28.0, 32.0, -31.0, -29.0, -23.0, -29.0, -28.0, -33.0,
	}
	frequency := make(map[float64]int)
	for _, t := range temperature {
		frequency[t]++
	}
	for t, num := range frequency {
		fmt.Printf("%+.2f の出現は%d回です\n", t, num)
	}
}

```