GO言語基礎①（package/function/for/if/switch/struct/point/arrays/slice）

# Go言語のメリット・デメリット

## メリット
* 文法がシンプルでわかりやすい
    * ライブラリが豊富なため簡潔に書くことができる
* 処理速度が速い  
    * 直接機械語に変換するためコンパイルが早い
    * 並列処理を簡潔に書くことができる。`goroutine`や`channel`を利用することで大量データの並列処理が可能
* シングルバイナリ、クロスコンパイルにより環境依存を減らすことができる

## デメリット
* コードの継承がない(enableにより似たような機能はある)  
→詳細は以下記事を参照  
[Go言語で「embedded で継承ができる」と思わないほうがいいのはなぜか？](https://qiita.com/Maki-Daisuke/items/511b8989e528f7c70f80)
* Genericsがない  
→使えるようになったらしい  
[Goに導入されるGenericsについてまとめてみた](https://qiita.com/shiei_kawa/items/5208a50634298d591e8c)
* 例外がない(エラーは値として処理)  
javaの場合以下のようにエラーを飛ばしますが
    
```java
    throw new Exception(...)
```  

goでは以下のような記載になります。

```go
// 何かの処理の戻り値にエラーが存在する場合
if err != nil {
    // ログ出力で処理終了
    log.Fatal(err)
}
```

#  Javaとの違い
## クラスではなく構造体で処理を紐付ける
クラスで行いたい処理としては以下のことがメインとなります。

* 処理毎によるメソッドの切り分け
* 処理に必要な関数、変数、定数の定義

Go言語では`struct`を用いて行います。

```go
package main

import (
	"fmt"
)

type Human struct {
	name string
	age  int
}

func (h Human) SayName() string {
	return h.name + "です。"
}

func main() {
	h := Human{"Mike", 10}
	fmt.Println(h, h.name, h.age)
	fmt.Println(h.SayName())
}
```
```:実行結果
{Mike 10} Mike 10
Mikeです。
```

上記では`Human`という`struct`を利用してクラス変数を定義しています。
`Human`にたいしてあたいを入れることにより、その変数、クラス関数を利用することができます。

## 継承が存在しない（似たような機能`Embedded`は存在する）
goにおいて継承は存在しません。その代わりにEmbeddedは存在します。
厳密にはクラスと違う部分もあるのですが、気になる場合は下記記事を参考にしてください。
[Go言語で「embedded で継承ができる」と思わないほうがいいのはなぜか？](https://qiita.com/Maki-Daisuke/items/511b8989e528f7c70f80)
今回は`Human`を親クラス、`Japanese`を子クラスとして記述します。

```go
package main

import (
	"fmt"
	"strconv"
)

type Human struct {
	name string
	age  int
}

type Japanese struct {
	Human
	weight int
}

func (h Human) SayName() string {
	return h.name + "です。"
}

func (h Human) SayAge() string {
	return strconv.Itoa(h.age) + "です。"
}

func (j Japanese) SayName() string {
	return "初めまして" + j.name + "です。"
}

func New(name string, age int, weight int) *Japanese {
	return &Japanese{Human{name, age}, weight}
}

func main() {
	// 初期化 
	j := New("Mike", 20, 55)
	// 親の関数を呼び出せていること
	fmt.Println(j.SayAge())
	// オーバーライドされていること
	fmt.Println(j.SayName())
}
```

```:実行結果
20です。
初めましてMikeです。
```

`Human`,`Japanese`にSayName関数を実装してオーバーライドされるか、親クラスの関数の呼び出しが可能か確認しました。
実行結果の通り親クラスの関数の呼び出し、オーバーライドが行えていることがわかります。
`Embedded`により、オブジェクト指向の特徴である。継承、ポリモーフィズムといった機能が実装できることがわかります。

# 基本文法

## パッケージ
Goではプログラムをpackageごとに分割しています。
importすることで他パッケージの利用もできます。
Goでは大文字で始まるものがPublic、この字で始まるものがPrivateとされるため、大文字始まりの定数や関数を呼び出すことができます。

```go
package main

import (
	"fmt"
	"strconv"
)

func main() {
	fmt.Println("Hello!");
}
```
## function(ファンクション):関数
Goではファンクションに処理を書きます。Javaでいうメソッドです。
大文字であればPublic、小文字であればPrivateで利用できます。
以下のように定義されます。

```go
func  <関数名>([引数]) [戻り値の型] {
    [関数の本体]
}
```

```Go
func (j Japanese) SayName() string {
	return "初めまして" + j.name + "です。"
}

func New(name string, age int, weight int) *Japanese {
	return &Japanese{Human{name, age}, weight}
}
```

先ほど継承の例で挙げた例を参考にすると、
SayNameメソッドはJapanese構造体に付随されており、引数はなし、戻り値はstringとされています。
Newメソッドは引数はname、age、weightとされ、Japanese構造体のポインタを返却しています。
※構造体とポインタはのちにて説明します

## 変数・定数
変数はvar、定数はconstにより定義します。
これに関してもPublic、Privateは大文字小文字で決まります。
宣言時は変数名、型の順で記述します。直接文字列、数値を入れる場合は型定義の必要がありません。
変数に値を代入したい場合は`:=`を利用することで宣言記述を省略できます。
定数の場合は`:=`を利用できません
定数で宣言できるのは`string``bool``character``numeric`のみです。

```go
var name1 string
var name2 = "Mike"

const age1 int
const age2 = 1

func main() {
	name3 := "Jessica"
}
```

## for/if/Switch
Switch/if条件/forループは`()`で囲む必要がなく記載ができる。`{}`の括りは必要。
Switch文はJavaではbreakでswitch文を抜けますがGo言語ではbreakは不要です。
Switch文は`fallthrough`を利用することでcase文で

```go
func main() {
	sum := 0
	for i := 0;i < 10;i++ {
		sum += 1;
		if sum<5 {
			fmt.Println("合計値が5以上")
		}
	}
	result := judge()
}

func judge() string {
	switch sum
	case sum == 5:
		return "合計値が正しくないよ"
	case sum == 10:
		return "合計値が正しいよ"
	default:
		return "想定値以外"
}
```
## struct(ストラクト):構造体
Goでは構造体にそのパッケージで利用する変数を定義します。
Javaでいうクラスに当たります。継承の記述説明を行った時同様に、処理を持たせることもできます。
`type 構造体名 struct {}`で宣言することができます。フィールド変数を呼び出すときは`構造体名.変数名`にて利用することができます。
ストラクトの初期化には「直接変数に値を入れる」「ストラクトの記載順で値を入れる」「フィールド名を指定して値を入れる」の３パターンがあります。

```Go
type Human struct {
	name string
	age  int
}

func (h Human) SayName() string {
	return h.name + "です。"
}


func New(name string, age int) *Human {
	// ストラクトの順に値を入れる
	return &Human{name, age}
}

func main() {
	// 初期化 
	h := New("Mike", 20)
	// Humanストラクトの変数呼び出し
	fmt.Println(h.name)
	// Humanストラクトの処理呼び出し
	fmt.Println(h.SayAge())

	// フィールド名指定で初期化する
	Alex := Human{name: "Alex", age: 10};
	// ストラクトに直接値を入れる
	Alex.age = 20
}
```
## point(ポインタ):メモリアドレス
ポインタはメモリのアドレス情報のことです。
GO言語では`&`を変数、構造体の前につけることでアドレスの取得（ポインタの取得）ができます。
また、`*`を変数名の前に記述することでポインタ型で変数宣言が可能です。
ポインタの存在意義が分からない場合はこちらの記事を参考にしてください
[Goで学ぶポインタとアドレス](https://qiita.com/Sekky0905/items/447efa04a95e3fec217f)

```go
type Human struct {
	name string
	age  int
}

func main() {
	// Human型で宣言
	h1 := Human{"Mike", 20}
	fmt.Println(h1)
	// Human型の別ストラクトの宣言
	h2 := h1
	h2.name = "Alex"
	fmt.Println(h2)
	fmt.Println(h1)
	// ポインタ型で宣言
	h3 := &h1
	h3.name = "Alex"
	fmt.Println(h3)
	fmt.Println(h1)
}
```
```:実行結果
{Mike 20}
{Alex 20}
{Mike 20}
&{Alex 20}
{Alex 20}
```

Human型で宣言した場合はh2には代入できているが、h1に反映できていない。これを値渡しという。
ポインタ型で宣言した場合は大元のHuman型で宣言した値に対して代入されていることがわかる。これを参照渡しという。
## 配列
配列とは、同じ型を持つ値（要素）を並べたものです。
複数の宣言方法があります。
最初に宣言した配列のサイズを変えることはできません。

```:宣言方法
var 変数名 [長さ]型
var 変数名 [長さ]型 = [大きさ]型{初期値1, 初期値n} 
変数名 := [...]型{初期値１, 初期値n}
```

```go
// 宣言方法１
var Names1 [2]string

// 宣言方法２
var Names2 [2]string = [2]string{"Mike", "Alex"}

// 宣言方法３
var Names3 = [...]string{"Mike", "Alex"}

func main() {
	// 値の取得
	fmt.Println(Names2[0])
	fmt.Println(Names2[1])
	fmt.Println(Names1, Names2, Names3)
}
```
``` :実行結果
Mike
Alex
[ ] [Mike Alex] [Mike Alex]
```

## slice(スライス):要素指定が必要ない配列
配列とは異なり長さ指定の必要がない。
別の配列から要素を取り出し参照する形での宣言やmake()を利用した宣言が可能。宣言時に値を入れることはできない。`make(型,長さ,容量)`で宣言が可能です。容量は省略が可能で、省略した場合長さと同じ値とされます。
配列とは異なり要素の追加が可能です(append)。
数値の意味合いは以下のようになります。

|操作|意味|
|--|--|
|Slice[start:end]|start から end - 1 まで|
|Slice[start:]|start から最後尾まで|
|Slice[:end]|先頭から end - 1 まで|
|Slice[:]|先頭から最後尾まで|

長さ(length)と容量(capacity)の両方を持っています。
型が一致している場合、他のスライスに代入することが可能です。
スライスのゼロ値はnil。

```:宣言方法
var 変数名 []型
var 変数名 = make([]型,2,2)
```
```go
	var arr [2]string = [2]string{"Mike", "Alex"}

	var slice1 []string
	var slice2 []string = []string{"Mike", "Alex", "jessica"}

	// 配列からの代入
	var slice3 []string = arr[0:2]

	// makeを使用した宣言
	// make(型,長さ,容量)スライスオブジェクトの確保、初期化を行う。容量は省略可能
	var slice4 = make([]string, 2, 4)

	// appendによる追加
	var slice5 []string = []string{"Mike", "Alex"}
	slice5 = append(slice5, "jessica")

	fmt.Println(slice1, slice2, slice3, slice4, slice5)
	fmt.Println(len(slice2), cap(slice2))
```
```:実行結果
[] [Mike Alex jessica] [Mike Alex] [ ] [Mike Alex jessica]
3 3
```

# 次の記事
[GO言語基礎②（defer/map/range/Interface/goroutine/channel）](https://qiita.com/kenRp01/items/70e63c25567048071feb)

# 参考記事
[go言語 メリットとデメリット](https://www.dragonarrow.work/articles/232)
[JavaプログラマーのためのGo言語入門](https://future-architect.github.io/articles/20200311/)
[Go言語でハマったことメモ（クラス・継承）](https://www.kwbtblog.com/entry/2020/04/07/055735)
[【Go】基本文法総まとめ](https://qiita.com/k-penguin-sato/items/deaeab18aa416496e273)