3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Go 触ってみたけど、違和感多め。

Posted at

image.png

はじめに

仕事で Go のコードを追いかける事があったので、ちょっと Go に興味が湧き触ってみました。
ページ下部の"参考"に記載されている Microsoft のサイトでハンズオン。ポイントと感想を記載します

開発環境

  • OS : Windows 11 Pro
  • go : 1.23.3 windows/amd64
  • Cursor(IDE) : 0.42.3

Go とは?

  • こちらに解りやすくまとまってます
  • ざっくり言うと
    • シンプルで効率的
      • Go は直感的な構文と高速なコンパイル速度を特徴としており、学習しやすく使いやすい設計
    • 高い並行性
      • Go のゴルーチンとチャネルにより、並列処理を簡潔かつ効率的に実現できる
    • 幅広い用途
      • サーバーサイド開発、クラウドアプリケーション、システムプログラムなど、多様な領域で活用できる

インストール

Go ワークスペースを構成する

  • ワークスペースを構成するには、ローカルの Go 環境変数で、Go プロジェクト フォルダーの場所を指定します
    > [Environment]::SetEnvironmentVariable("GOPATH", "<project-folder>", "User")
    
  • ただし、Go 1.13 以降は、下記になります
    • 反映には、プロンプトの再起動が必要! 20 分ぐらい悩みました
    go env -w GOPATH=<project-folder>
    

Go ワークスペース フォルダー

  • Go ワークスペースには、次の 3 つの基本フォルダーがあります
    • bin
      • アプリケーションの実行可能ファイルを含めます
    • src
      • ワークステーションに存在するすべてのアプリケーションのソース コードを含めます
    • pkg
      • 使用可能なライブラリのコンパイル済みバージョンを含めます。 再コンパイルせずに、コンパイラから、これらのライブラリにリンクできます

スゴク違和感。 慣れなんですかね

サンドボックス環境

  • Go Playground が用意されていて、サクッと触れるのは素晴らしいです

変数、関数

rune

  • int32 ではダメなんですか?

uint

  • まぁ、たまに必要になるかな

使用しない変数

  • 使用しない変数を宣言すると Go のエラーが出る。IDE で波線出てても、たまに消し忘れるからいいですね。ただ、逆に関数の戻り値とかで、利用しない変数は _ で表現する手間はありますね

関数

  • 戻り値に名前を設定すると、return に何も記載しないのは見難い(断捨離しすぎ)

    func sum(number1 string, number2 string) (result int) {
        int1, _ := strconv.Atoi(number1)
        int2, _ := strconv.Atoi(number2)
        result = int1 + int2
        return
    }
    
  • 複数の値を返すのが気持ち悪い

    func calc(number1 string, number2 string) (sum int, mul int) {
        int1, _ := strconv.Atoi(number1)
        int2, _ := strconv.Atoi(number2)
        sum = int1 + int2
        mul = int1 * int2
        return
    }
    
    func main() {
        sum, mul := calc(os.Args[1], os.Args[2])
        fmt.Println("Sum:", sum)
        fmt.Println("Mul:", mul)
    }
    
  • 関数のパラメーター値 (ポインター)は慣れるまで注意が必要(パット見で見逃す)

    func main() {
        firstName := "John"
        updateName(&firstName)
        fmt.Println(firstName)
    }
    
    func updateName(name *string) {
        *name = "David"
    }
    

パッケージ

パッケージ名とファイル名

  • Java のファイル名とクラス名と同じようにファイル名とパッケージ名は別でも OK
    • ただし、別にすると"モジュール参照"で分かり難くなる

モジュール(パッケージ)

  • Go のパッケージは、Java のパッケージとは違う。Java のクラス名みたいなもの
    下記の参照からgo_helloworldgo_calculatorの関係を良く見てください!

外部パッケージを参照(パッケージの公開)

  • モジュール作成にはコマンドが必要
    • > go mod init github.com/[モジュールパッケージ]
    • "go.mod" ファイルが生成される
  • GitHub で公開。コード上に github.com/XXX とベタで記載されてるのは変な感じ

制御フロー

fallthrough

  • switch では break を記載しない。1 case で switch ブロックが終了になるのは、解り易くて良いと思う
    • 他の言語と同様にフォールスルーするには fallthrough を case の最後に記載

panic / recover

  • java のtry/catch な感じだけど、書く場所には慣れが必要。特に recover は感覚とは違う
    func highlow(high int, low int) {
    	if high < low {
    		fmt.Println("Panic!")
    		panic("highlow() low greater than high")
    	}
    	defer fmt.Println("Deferred: highlow(", high, ",", low, ")")
    	fmt.Println("Call: highlow(", high, ",", low, ")")
    
    	highlow(high, low+1)
    }
    
    func main() {
    	defer func() {
    		handler := recover()
    		if handler != nil {
    			fmt.Println("main(): recover", handler)
    		}
    	}()
    
    	highlow(2, 0)
    	fmt.Println("Program finished successfully!")
    }
    

データ型

配列、スライス、マップ

  • make で初期化。new と似ているけど別物

ログ

ログのファイルパス設定

```
log.SetOutput(file)
```

log 以外のログ記録フレームワーク

  • Logrus、zerolog、zap、Apex

メソッド/インターフェース

メソッド

  • Java より柔軟だけど、"レシーバー"に違和感
  • メソッドで変数を更新する場合は、ポインターを利用する
    type triangle struct {
        size int
    }
    
    func (t triangle) perimeter() int {
        return t.size * 3
    }
    func (t *triangle) doubleSize() {
        t.size *= 2
    }
    

インターフェイス

  • インターフェースと実装に関連がない
    type Shape interface {
        Perimeter() float64
        Area() float64
    }
    type Square struct {
        size float64
    }
    
    func (s Square) Area() float64 {
        return s.size * s.size
    }
    
    func (s Square) Perimeter() float64 {
        return s.size * 4
    }
    func main() {
        var s Shape = Square{3} ←ここインターフェースと実装がマッチ
        fmt.Printf("%T\n", s)
        fmt.Println("Area: ", s.Area())
        fmt.Println("Perimeter:", s.Perimeter())
    }
    

コンカレンシー

Go には、同時実行プログラムを作成するためのスタイルが 2 つある。
1 つは、他の言語と同様に、スレッドを使用する従来のスタイル。もう 1 つは、goroutines という独立したアクティビティ間で値が渡される Go のスタイル

ざっくり言うと、go で平行処理する時には "goroutine"(スレッドみたいな) を利用する。

goroutine (ゴールーチン)

```
func main() {
	start := time.Now()

	apis := []string{
		"https://management.azure.com",
		"https://dev.azure.com",
		"https://api.github.com",
		"https://outlook.office.com/",
		"https://api.somewhereintheinternet.com/",
		"https://graph.microsoft.com",
	}

	for _, api := range apis {
		go checkAPI(api) // ここが同時実行される!
	}

	elapsed := time.Since(start)
	fmt.Printf("Done! It took %v seconds!\n", elapsed.Seconds())
}

func checkAPI(api string) {
	_, err := http.Get(api)
	if err != nil {
		fmt.Printf("ERROR: %s is down!\n", api)
		return
	}

	fmt.Printf("SUCCESS: %s is up and running!\n", api)
}
```

goroutine の特徴

  • 処理順序が保証されない
  • メインゴルーチン(main)が終わると他のゴルーチンの終了を待たずにプログラム全体が終了する

チャネル

goroutine 間で値を送信する必要があるとき、チャネルを使用する。

ざっくり言うと、異なるスレッド(goroutine)同士で、値をやりとり(送受信)すること。
なんとなく、別空間で流しっぱでない(戻りを待つ)場合にチャンネルを使うイメージしてます

チャンネルのいろいろ

  • バッファ有り/無し
    • バッファーありのチャネルの場合、プログラムがブロックされずにデータが送受信され、バッファーありのチャネルはキューのように動作する
  • チャネルの方向
    • パラメータで指定したチャンネルへの方向(送信/受信)と異なる方向にするとコンパイルエラーになる
  • 多重化
    • 複数チャンネルの制御。イベント発生での待機など

チャンネルの理解

言葉だけだと理解できないので、ページ下部の GitHub から go_goroutine リポジトリをご覧ください。

テスト(ユニットテスト)

Java の Junit とほぼ同じ

名称

  • ファイル名 : XXX_test.go
  • 関数名 : TestXXX(t *testing.T)

インポート

  • import "testing"

サンプルアプリ

銀行業務をイメージしたサンプルアプリ。ページ下部の GitHub から go_bankcore, go_bankapi リポジトリをご覧ください。

おわりに

まだ、1 歩も進めてないけど、なんとなく切り分けは出来るようになりました。
Go は違和感多めですが、手軽に始められる言語で好感を持てました。特に goroutine とチャンネルを使った平行処理は他のサービスなどと連携する際には使いどころが多いと思います。

ダラダラと感想を書いてしまったので、次回の投稿はもっとポイントを絞って見やすい記事にしたいです。


参考(感謝)

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?