GOの基礎：Rails視点のgolang

- エラーハンドリング
    - 処理実行時のエラー有無は出力の2つ目に出る
    - 自動的にハンドリングするわけではないので毎回errのチェックをする必要がある
    
    ```go
    _, err := func()
    if err != nil {
    	fmt.Println(err)
    }
    ```
<br>
- メモリ解放
    - 変数定義の際には完了後クローズを宣言しないとメモリリークに繋がる？
        - というよりは単純に最後に実行したい処理を書いてるだけか
    - この`defer`は、呼び出し元の関数(ここでは`main`)がreturnするまで処理を遅延させて、return時に実行してくれるようにできる文法です。
    
    ```go
    defer f.Close()
    ```
<br>

- errのような変数は使い回す
    - 基本的には処理直後のエラーハンドリングでしか使わない
    - 終わった次の関数のエラーハンドリングでも同じ変数を使う
    - `:=`ではなく`=` を使う
<br>

- Goの変数名の慣習
    - Goでは、できるだけ変数名を短くするという慣習があります
    - err(error), cfg(config), msg(message)など
<br>

- クラスと構造体の違い
    - 同じ
        - クラスと構造体は非常に似た概念で、他の言語でクラスが利用される多くの場面でGoでは構造体が利用されます。
    - 違い
        - クラス変数・クラスメソッドのような、クラスの中で共通の値や処理が、構造体には存在しない。
        - クラスと違って「継承」機能がない
<br>

- ポインタ型
    - `*`はポイント型なので&aのようなポインタを引数に渡す（変数の値ではなく）
    - つまり、以下はstringの値が格納されたポインタ型を引数に取る
    
    ```go
    func sayHello(name *string) {
    	fmt.Printf("Hello, %s\n", *name)
    }
    ```
    
<br>

- ポインターをどのように使うのか
    - 1. 構造体などのデータ量が大きい型を扱うとき
    
    ```go
    	user := &User{ // &をつけることでポインタ型になる
    		id:   "1",
    		name: "John Lennon",
    		age:  30,
    	}
    ```
    
    - 2. 関数・メソッドの内部などから値を書き換えをしたいとき
    
    ```go
    type User struct {
    	id   string
    	name string
    	age  int
    }
    
    func (u *User) IncrementAge() {
    	u.age++ // intなどの数字系の値をインクリメント(+1)する処理
    }
    
    func main() {
    	user := &User{ // &をつけることでポインタ型になる
    		id:   "1",
    		name: "John Lennon",
    		age:  30,
    	}
    
    	user.IncrementAge()
    	fmt.Println(user.age)
    	// => 31
    }
    ```
    
    - 3. nullが存在しない型にnil(null)を許容させたいとき
        - デフォルト値
            - string,intなどのGoの基本型には、nil(null)がありません。
            - それらの型の変数等は、定義された時点で、デフォルト値を持ちます。
            - デフォルト値とは、例えば、stringの場合は空文字列`""`、 intの場合は`0`です。
            - そのため、それらのデフォルト値とnilを区別できるようにするために、nilを許容しているポインタ型で扱うという方法があります。
        - 例外
            - ただし、`err` は `error` 型であり、Go の基本型（`string`, `int` など）とは異なる扱いになる
            - Go において `error` 型は **インターフェース型** です。インターフェース型は、値が何も設定されていない場合 `nil` となります。
<br>

- ポインタの注意点
    1. 意図せぬ値の変更に注意する
    2. nil(null)に注意する
<br>

- 命名規則
    - 構造体
        - メンバー変数は命名規則があり、先頭1文字が大文字か小文字かで挙動が変わります。
            - 大文字で始めると、パッケージ外からでもアクセスできう
            - 小文字で始めると、パッケージ内のみアクセスできる
<br>

- ファイル内での定義順序
    
    ```go
    package main
    
    import (
        "fmt"
        "log"
        "os"
    )
    
    // 1. 定数
    const (
        AppName  = "MyApp"
        Version  = "1.0.0"
    )
    
    // 2. グローバル変数
    var (
        debugMode bool
        logger    *log.Logger
    )
    
    // 3. 構造体の定義
    type User struct {
        ID   int
        Name string
        Age  int
    }
    
    // 4. インターフェース
    type Greeter interface {
        Greet() string
    }
    
    // 5. メソッド
    func (u *User) Greet() string {
        return "Hello, " + u.Name
    }
    
    // 6. 通常の関数
    func add(a, b int) int {
        return a + b
    }
    
    // 7. init 関数
    func init() {
        debugMode = true
        logger = log.New(os.Stdout, "LOG: ", log.LstdFlags)
    }
    
    // 8. main 関数
    func main() {
        fmt.Println("Hello, Go!")
        u := User{ID: 1, Name: "Alice", Age: 25}
        fmt.Println(u.Greet())
    }
    
    ```
    
<br>

- 変数定義
    
    
    | 宣言方法 | 例 | 使える場所 | 特徴 |
    | --- | --- | --- | --- |
    | `:=` | `a := 10` | 関数内のみ | **型推論あり、変更可** |
    | `var` | `var a = 10` | 関数内・関数外 | **型指定可能、変更可** |
    | `const` | `const Pi = 3.14` | 関数内・関数外 | **変更不可** |
<br>

- Go の `const` の制約
    - `const` は コンパイル時に値が決定できる必要がある。
    - `const` にできるのは、数値リテラル, 文字列リテラル, `true/false` などの単純な値のみ。
    - 配列 (`[N]T`) や スライス (`[]T`), マップ (`map[T]U`) などの 複合データ型 は `const` にできない。
    - つまり、この `favicon` は スライス `[]byte`（バイト列） であるため、コンパイル時に確定できず `const` にできない のです。

<br>

- パブリックアクセスとプライベートアクセス
    - それは、**先頭の文字が大文字かどうか**です。
    - 関数でも変数でも型でも、先頭が大文字が始まるものはパッケージ外からアクセス可能で、小文字で始まるものはパッケージ内部専用のものとなります。
- スライスと配列
    - 配列：固定長
        - `var msgs [2]string`
            - 番号指定で入力可能
            
            ```
            msgs[0] = "Hello"
            msgs[1] = "こんにちは"
            ```
            
    - スライス：可変長
        - `var msgs []string`
            - 独自関数で入力
            
            ```go
            msgs = append(msgs, "こんにちは")
            ```
            
<br>

- パッケージ管理
    - rails：Gemfile, Gemfiie.lock
    - go：go.mod, go.sum
<br>

- パッケージのimport順序
    - 標準->外部->内部の順番
<br>

- インターフェースを用いた共通化
    1. 処理の拡張・共通化を可能にする
    2. 具体的な挙動を隠蔽して、抽象化・疎結合化する
    3. テストでモックを作る

```go
# 天気構造体
type WeatherInfo struct {
	temperature int
	weather     string
}

# 天気関数
func (w *WeatherInfo) Report() string {
	return fmt.Sprintf("天気: %s, 気温: %v度", w.weather, w.temperature)
}

# 投資構造体
type StockInfo struct {
	average int
}

# 投資関数
func (s *StockInfo) Report() string {
	return fmt.Sprintf("平均株価: %v円", s.average)
}

# 天気と投資の共通化インターフェース
type Reporter interface {
	Report() string
}

# 共通引数の関数
func PrintNews(r Reporter) { 
	fmt.Println("今日のニュースです。 %s", r.Report())
}

# 利用例
w := &WeatherInfo{
	temperature: 20,
	weather:     "晴れ",
}
s := &StockInfo{
	average: 30000,
}
PrintNews(w)
// => 今日のニュースです。 天気: 晴れ, 気温: 20度
PrintNews(s)
// => 今日のニュースです。平均株価: 30000円
```
<br>

- コマンド引数の定義指定
    
    ```go
    outputPath := flag.String("o", "./image.png", "Path to output file")
    ```
    

<br>

- Closeの目的と対象
- 対象
    - **クローズするべきもの**
        - **`resp.Body`（HTTPレスポンスのボディ）**
            - HTTPレスポンスを処理する際に、`resp.Body`を使用した後に`Close()`を呼び出すことが重要です。
            - これをしないと、接続がクローズされず、リソース（特にソケット）が解放されません。こ
            - れがメモリリークや接続の枯渇につながる可能性があります。
        - **ファイルやネットワーク接続（`file.Close()`や`conn.Close()`）**
            - ファイルやネットワーク接続も同様に、使用後にクローズしないと、リソースが解放されずに、最終的にメモリリークやリソース枯渇が発生することがあります。
    - **クローズしなくて良いもの**
        - **一部のリソース管理を自動で行うもの**: Goランタイムが自動的に管理するリソース（例えば、`sync.Mutex`や`sync.WaitGroup`などのロックオブジェクト）については、手動で閉じる必要はありません。これらは明示的にリソースを解放することが求められないからです。
- 目的
    - **メモリリーク対策**
        - リソースを使い終わった後に適切に解放しないと、メモリ上にリソースの参照が残り、ガーベジコレクションがそれらを解放しない場合があります。
        - 特に、`resp.Body`のようなストリームリソースはクローズを忘れると、メモリや接続が無限に消費され続ける原因となります。
    - **接続の枯渇対策**
        - HTTPリクエストなどでは、未クローズの接続が積み重なると、サーバーが接続できない状態になったり、システム全体のリソースが枯渇することがあります。