Go言語学習メモ

# 前書き
golangはシンプルな言語と言われていますが、実際勉強してみて、分かりづらかった点、十分に理解しないと、間違いやすい点などがあったので、 まとめてみました。

# :=, =の違い
- 初期化と再代入
  - `:=` は、変数の`宣言と初期化を同時`に行うことができます。var キーワード、変数名、代入演算子（=）を1つの簡潔な形式で書けます
  - `=` は、すでに宣言されている変数の`再代入`に使用されます
- スコープ
  - `:=` は、関数またはブロック内のみ使用できます
  - `=` は、コードのどこでも使用できます
- シャドーイング
(同名の新しい変数が宣言されるときに、発生)
  - `:=` は、ブロック内で既存のブロック外の変数をシャドーイング（新しい変数として扱う）します
  - `=` は、既存の変数のスコープに影響を与えず、シャドーイングが発生しない
シャドーイング例
    ```golang
    var a = 1
    var b = 1
    var c = 1
    
    func shadow1() int {
    	a := 2 // topレベルのaと関係ない、新しいlocalのaを宣言
    	return a
    }
    func unshadow() {
    	b = 2 // topレベルのbを上書きする
    }
    func shadow2() int {
    	var c int // topレベルのcと関係ない、新しいlocalのcを宣言
    	c = 2
    	return c
    }
    func main() {
    	shadow1()
    	unshadow()
    	shadow2()
    	fmt.Println(a) // 1 
    	fmt.Println(b) // topレベルのbが上書きされてる
    	fmt.Println(c) // 1
    }
    ```

# 関数のparameterはtypeによってpassed by reference、passed by valueが異なる
  - 例えば、sliceはPassed by reference, arrayはpassed by value
    ```golang
    package main
    
    import "fmt"
    
    type person struct {
    	name string
    }
    
    func changeSlice(s []int) {
    	s[1] = 333
    }
    
    func changeSlice2(s *[]int) {
    	t := *s
    	t[1] = 333
    }
    
    func unchangeArray(a [3]int) {
    	a[1] = 333
    }
    
    func changeArray(a *[3]int) {
    	a[1] = 333
    }
    
    func main() {
    	s := []int{1, 2, 3}
    	changeSlice(s)
    	fmt.Println(s)
    
    	t := []int{1, 2, 3}
    	changeSlice2(&t)
    	fmt.Println(t)
    
    	a := [3]int{1, 2, 3}
    	unchangeArray(a)
    	fmt.Println(a)
    
    	changeArray(&a)
    	fmt.Println(a)
    }
    
    ```

# slice vs array
- arrayはサイズが決めてる
- sliceはサイズが決まってない
    ```golang
    	var slice []int
    	var array [3]int
    
    	fmt.Println(slice) // []
    	fmt.Println(array) // [0 0 0]
    	fmt.Println(reflect.TypeOf(slice).Kind()) // slice
    	fmt.Println(reflect.TypeOf(array).Kind()) // array
     ```

- loop
    ```golang
        var a [6]int
    	var b []int = []int{0, 1, 2, 3, 4, 5}
    	for k, v := range a {
    		fmt.Printf("%d, %d\n", k, v)
    	}
    
    	for k, v := range b {
    		fmt.Printf("%d, %d\n", k, v)
    	}
     ```

# 関数、変数などをpackage外に公開するため、命名を大文字から始める必要がある
```golang
type User struct { // 公開
	ID int64
}

type user struct { // 非公開
	ID int64
}
```

# struct 構造体
フィールドがあるデータ構造
```golang
type Person struct {
    name string
    age  int
}

func main() {
    p := Person{name: "tom", age: 20}
    fmt.Print(p)
}
```

- structにmethodを定義する
  - methodはreceiverがある関数で、他の言語でのinstance methodみたいなものです
  - receiverはPassed by value, Passed by referenceの二種類がある

    ```golang
    package main
    
    import (
    	"fmt"
    )
    
    type person struct {
    	firstName string
    	lastName  string
    	age       int
    }
    
    // Passed by reference(パラメータがPointer type)
    // cがreceiverである
    func (c *person) name() string {
    	c.lastName = "changed"
    	return c.lastName + " " + c.firstName
    }
    
    // Passed by value
    // cがreceiverである
    func (c person) name2() string {
    	c.lastName = "no changed"
    	return c.lastName + " " + c.firstName
    }
    
    func main() {
    	p := person{firstName: "tom", lastName: "jerry", age: 4}
    	fmt.Println(p.name())
    	fmt.Println(p.lastName) // changed
    	p2 := person{firstName: "tom", lastName: "jerry", age: 4}
    	fmt.Println(p2.name2())
    	fmt.Println(p2.lastName) // jerry 元のまま
    }
    ```

- constructorが存在しない
独自の初期化処理を入れたい場合、factory functionを自分で定義する必要がある

    ```golang
    package main
    
    import (
    	"fmt"
    )
    
    type User struct {
    	id   int
    	name string
    }
    
    func NewUser(id int, name string) *User { // factory function
    	if name == "" {
    		name = "Anonymous　user"
    	}
    	return &User{id, name}
    }
    
    func main() {
    	// 初期化する方法
    	u := User{}     // ①
    	fmt.Println(u)  // {0 }
    	u1 := new(User) // ② new関数を使うと、pointerが設定される
    	fmt.Println(u1) // &{0 }
    	u2 := NewUser(1, "tom")
    	fmt.Println(u2) // &{1 tom}
    }
    ```

- embeded struct
    ```golang
    package main
    
    import (
    	"fmt"
    )
    
    type name struct {
    	first string
    	last  string
    }
    
    type User struct {
    	id   int
    	name name
    }
    
    type User2 struct {
    	id int
    	name // embeded struct
    }
    
    func main() {
    	u := User{name: struct{first: "first name", last: "last name"}}
    	fmt.Println(u.name.first)
    	// fmt.Println(u.first) //　エラー：　u.first undefined
    
    	u2 := User2{name: name{first: "first name2", last: "last name2"}}
    	// u2 := User2{first: "first name2", last: "last name2"} // 初期化するときはnameを指定する必要があります。ここではunknown field firstエラーが発生
    	fmt.Println(u2.name.first)
    	fmt.Println(u2.first) // アクセスするときは、nameを経由しなくても良い、railsのdelegateみたいなもの
    }
    ```
- embeded structは便利そうに見えるけど、注意点がある
  - embed先、元が同じ項目ある場合、分かりづらい
    ```golang
    package main
    
    import "fmt"
    
    type pet struct {
    	name string
    }
    
    type person struct {
    	name string
    	pet
    }
    
    func main() {
    	p := person{name: "Deitch era", pet: pet{name: "tom"}}
    	fmt.Println(p.name)  // nameはpersonの？ petの？ 
    }
    ```
  - embedされてstructの項目がpublicになって、必要以上の詳細がpublicなることが発生する

    ```golang
    package model
    
    type Person struct {
    	pet1
    	pet2 pet2
    }
    
    type pet1 struct {
    	Foods []string
    }
    
    type pet2 struct {
    	Foods []string
    }
    
    func (p *Person) FeedPet2(food string) bool {
    	if food == "唐辛子" {
    		return false
    	}
    	p.pet2.Foods = append(p.pet2.Foods, food)
    	return true
    }

    // 以下は別のpackage
    func main() {
	  p := Person{}
      // pet1のFoodsは外部packageにpublicされてるので、直接pet1に何もあげることができる
	  p.Foods = append(p.Foods, "唐辛子") 
	  fmt.Println(p.Foods) // [唐辛子]

      // p.pet2やp.pet2のFoodsも直接アクセスできないので、publicしたFeedPet2 methodは利用するしかない
	  p.FeedPet2("唐辛子")
	  fmt.Println(p.pet2.Foods) // []
    }
    ```

- anonymous struct
    ```golang
    package main
    
    import (
    	"fmt"
    )
    
    type User struct {
    	id   int
    	name struct { // anonymous struct
    		first string
    		last  string
    	}
    }
    
    func rect(width int, height int) struct{ width, height int } {
    	a := struct{ width, height int }{width, height} // anonymous struct
    	return a
    }
    
    func main() {
    	a := rect(2, 4)
    	fmt.Println(a.width)
    
    	u := User{id: 5, name: struct {
    		first string
    		last  string
    	}{first: "first name", last: "last name"}}
    	fmt.Println(u)
    }
    ```

# Interfaces　
- Interfaces are implemented implicitly
- 外部packageのstructにいろんなmethodがあって、自分が依存してるmethodだけをinterfaceとして定義して、利用できます
```golang
package main

import (
	"fmt"
	"time"
)

type unixDate interface {
	Unix() int64
}

func main() {
	var date unixDate
	date = time.Date(2022, 4, 1, 9, 0, 0, 0, time.Local)
    // time.DateのUnix() methodとunixDate interfaceのUnix()のfunction signatureが同じなので、time.DateがunixDate interfaceを実現したことになる
	fmt.Println(date.Unix())
	//fmt.Println(date.Year()) // time.DateにはYear() methodがありますが、unixDate interfaceにはないので、利用できない
}
```

# Function is First Class
functionを値として使える

```golang
package main

import "fmt"

type filterFunc[E any] func(E) bool // 関数型のtype定義

func Filter[E any](s []E, f filterFunc[E]) []E {
	result := []E{}
	for _, v := range s {
		if f(v) {
			result = append(result, v)
		}
	}
	return result
}

func onlyEven(v int) bool {
	return v%2 == 0
}

var filterEven = onlyEven // 関数を変数に設定できる

func main() {
	s := []int{1, 2, 3, 4}
	fmt.Println(Filter(s, onlyEven)) // 関数を関数の引数に渡す
	fmt.Println(Filter(s, filterEven))
}

```

# deferの役割
- 関数がreturnするまでに処理の実行を遅延する仕組みで、実行順番はLIFO

```golang
package main

import (
	"fmt"
)

func trace(s string) string {
	fmt.Println("entering:", s)
	return s
}

func un(s string) {
	fmt.Println("leaving:", s)
}

func a() {
	defer un(trace("a"))
	fmt.Println("in a")
}

func b() {
	defer un(trace("b"))
	fmt.Println("in b")
	a()
	defer fmt.Println("finish b")
}

func main() {
	b()
	fmt.Println("finish main")
}

// 出力は
// entering: b
// in b
// entering: a
// in a
// leaving: a
// finish b
// leaving: b
// finish main
```
- 利用シーン、例えば、resourceの回収に使う
```golang
func Contents(filename string) (string, error) {
    f, err := os.Open(filename)
    if err != nil {
        return "", err
    }
    defer f.Close()  // f.Close will run when we're finished.

    .....
}
```

# type assertion
typeをany(interface{})に宣言した場合、実際の値のtypeをして扱う前にType assertionを行う必要がある
```golang
    var a any
	a = "2,3"
	fmt.Println(strings.Split(a, ",")) // errorが発生： ./prog.go:11:28: cannot use a (variable of type any) as string value in argument to strings.Split: need type assertion
	fmt.Println(strings.Split(a.(string), ",")) // OK
```

# pointer
- pointerは値の住所って理解すれば、分かりやすいです
- `*`は使うところにより、意味が異なる
  - typeとして使う場合、pointer typeを意味する。 `var x *int` はintのpointer(住所)を意味する
  - 操作として使う場合、`*p`はpointerが指してる値をアクセスする

```golang
package main

import "fmt"

func main() {
	i, j := 42, 2701

	p := &i         // &でiに格納した42の住所を取得してpに設定する
    fmt.Println(p)
	fmt.Println(*p) // *で、pointerが指してる値をアクセスできる
	*p = 21         // pointerが指してる値を入れ替える
	fmt.Println(i)  // iが21になる
}
```

```golang
package main

import "fmt"

func unchanged(i int) {
	i = 2
}

func changed(i *int) { // iはintのpointer type
	*i = 2
}

func main() {
	i := 1
	unchanged(i)

	fmt.Println(i)
	changed(&i) // pointer(住所)を渡す

	fmt.Println(i)
}
```

```golang
package main

import "fmt"

type person struct {
	name string
}

func changename1(p *person) {
	p.name = "xxx" // struct中の項目を変更するときは*p.nameにする必要がない
}

//	func changename2(p *person) {
//		*p.name = "xxx" // compile error
//	}

func main() {
	p := person{name: "tom"}
	changename1(&p)
	fmt.Println(p)
}
```

# tag
struct fieldに付加されるメタデータです。さまざまなツールやライブラリに追加情報や指示を提供します。
書き方： field型の後に、tagName:"value"をバッククォート(`)で囲みます。
例えば、tagでvalidationを実現することが可能です

```golang
package main

import (
	"fmt"
	"reflect"
)

type MyStruct struct {
	Name string `validate:"notzero"`
	Age  int    `validate:"notzero"`
}

func validateStruct(s interface{}) []error {
	var errors []error
	v := reflect.ValueOf(s)
	t := v.Type()

	for i := 0; i < v.NumField(); i++ {
		field := t.Field(i)
		tag := field.Tag.Get("validate")

		if tag == "notzero" {
			fieldValue := v.Field(i)
			zero := reflect.Zero(fieldValue.Type()).Interface()
			if fieldValue.Interface() == zero {
				errors = append(errors, fmt.Errorf("%s cannot be zero", field.Name))
			}
		}
	}

	return errors
}

func main() {
	err := validateStruct(MyStruct{"John", 30})
	fmt.Printf("Error: %s\n", err) // Error: []

	err = validateStruct(MyStruct{})
	fmt.Printf("Error: %s\n", err) // Error: [Name cannot be zero Age cannot be zero]

	err = validateStruct(MyStruct{"tom", 0})
	fmt.Printf("Error: %s\n", err) // Error: [Age cannot be zero]

	err = validateStruct(MyStruct{"", 2})
	fmt.Printf("Error: %s\n", err) // Error: [Name cannot be zero]

}
```

# zero valueは何？ nilは何？
宣言して、初期化されてない変数は自動でzero valueを設定されます。
例えば、
- intのzero valueは0
- booleanのzero valueはfalse
- stringのzero valueは""
- pointer, channel, func, interface, map, or slice typeのzero valueは`nil`です
  - `nil`は0, false, ""みたいに、特別なzero valueで考えれば良いと思います。

```golang
package main

import "fmt"

func main() {
	var isTrue bool
	var age int
	var ch chan int
	var numbers []int
	fmt.Println(isTrue) // false
	fmt.Println(age) // 0
	fmt.Println(ch == nil) // true
	fmt.Println(numbers == nil) // true

	numbers = []int{1, 2, 3}
	fmt.Println(numbers == nil) // false
	numbers = nil
	fmt.Println(numbers == nil) // true
}
```

# 主に参考した資料
https://go.dev/doc/effective_go
https://www.youtube.com/watch?app=desktop&v=N0fIANJkwic
https://www.oreilly.com/library/view/100-go-mistakes/9781617299599/
https://bard.google.com/chat