Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go言語総合ガイド- 初学者のための学習資料

ymgc
October 02, 2024

Go言語総合ガイド- 初学者のための学習資料

ymgc

October 02, 2024
Tweet

More Decks by ymgc

Other Decks in Programming

Transcript

  1. 統合開発環境(IDE)の選択 Visual Studio Code + Go拡張機能 ▶ 軽量で多機能、無料で利用可能 - インテリセンス、デバッグ機能、コード補完など豊富な機能

    - GoLand(JetBrains製) ▶ Go専用のIDE、高度な機能と快適な開発環境 - 有料だが、学生や教育機関向けの無料ライセンスあり - 9
  2. プロジェクト構成 GOPATHの理解と設定 ▶ Goのワークスペースを指定する環境変数 - 通常は $HOME/go に設定 - Go

    Modulesの基本 ▶ Go 1.11以降で導入された依存関係管理システム - go mod init でプロジェクトを初期化 - go.mod ファイルで依存関係を管理 - 10
  3. 統合ツールチェーン:go testコマンド Goの標準テストフレームワークを使用したテスト実行 ▶ 使用例: go test ./... (すべてのパッケージをテスト) ▶

    テストカバレッジの計測も可能: go test -cover ./... ▶ ベンチマークテストの実行: go test -bench=. ▶ 12
  4. 変数宣言 明示的な宣言: var name string = "Gopher" ▶ 型推論を使用した短縮構文: name

    := "Gopher" ▶ 複数変数の同時宣言: var x, y int = 10, 20 ▶ 定数宣言: const Pi = 3.14159 ▶ 17
  5. 基本データ型 整数型:int, int8, int16, int32, int64, uint, uint8, uint16, uint32,

    uint64 ▶ 浮動小数点型:float32, float64 ▶ 複素数型:complex64, complex128 ▶ ブール型:bool ▶ 文字列型:string ▶ バイト型:byte(uint8の別名) ▶ ルーン型:rune(int32の別名、Unicodeコードポイントを表す) ▶ 19
  6. 複合データ型 type Person struct { Name string Age int }

    配列:固定長の要素の集合。 var a [5]int ▶ スライス:可変長の配列のようなデータ構造。 s := []int{1, 2, 3} ▶ マップ:キーと値のペアを格納。 m := map[string]int{"apple": 1, "banana": 2} ▶ 構造体:異なる型のフィールドを集めたもの。 ▶ 20
  7. 制御構造:if文 if x > 0 { fmt.Println("Positive") } else if

    x < 0 { fmt.Println("Negative") } else { fmt.Println("Zero") } if err := doSomething(); err != nil { // エラー処理 } 基本的な使い方: ▶ 初期化付きif文: ▶ 21
  8. 制御構造:for文 for i := 0; i < 5; i++ {

    fmt.Println(i) } n := 0 for n < 5 { n++ } for { // 処理 } 基本的なfor文: ▶ while的な使い方: ▶ 無限ループ: ▶ 22
  9. 制御構造:switch文 switch day { case "Monday": fmt.Println("It's Monday") case "Tuesday":

    fmt.Println("It's Tuesday") default: fmt.Println("It's another day") } switch { case n < 0: fmt.Println("Negative") case n > 0: fmt.Println("Positive") default: fmt.Println("Zero") } 基本的な使い方: ▶ 式を使ったswitch: ▶ 23
  10. defer文の使用法 f, err := os.Open("file.txt") if err != nil {

    return err } defer f.Close() // ファイル操作 関数の終了時に実行される処理を指定 ▶ リソースの解放やクリーンアップに便利 ▶ 例: ▶ 複数のdefer文がある場合、後入れ先出し(LIFO)で実行される ▶ 24
  11. 関数の定義と呼び出し func add(x int, y int) int { return x

    + y } func divide(x, y float64) (float64, error) { if y == 0 { return 0, errors.New("division by zero") } return x / y, nil } func rectangle(width, height int) (area, perimeter int) { area = width * height perimeter = 2 * (width + height) return // 名前付き戻り値を使用する場合、空のreturnで良い } 基本的な関数定義: ▶ 複数の戻り値: ▶ 名前付き戻り値: ▶ 27
  12. メソッドの定義 type Rectangle struct { Width, Height float64 } func

    (r Rectangle) Area() float64 { return r.Width * r.Height } func (r *Rectangle) Scale(factor float64) { r.Width *= factor r.Height *= factor } 構造体に対するメソッド: ▶ ポインタレシーバを使用したメソッド: ▶ 28
  13. 関数型プログラミングの要素 var compute func(int, int) int compute = func(x, y

    int) int { return x + y } result := compute(3, 4) // 7 func applyOperation(x, y int, op func(int, int) int) int { return op(x, y) } sum := applyOperation(5, 3, func(a, b int) int { return a + b }) // 8 関数を変数として扱う: ▶ 高階関数(関数を引数や戻り値として扱う関数) : ▶ 30
  14. 無名関数とクロージャ func() { fmt.Println("Hello, World!") }() func adder() func(int) int

    { sum := 0 return func(x int) int { sum += x return sum } } add := adder() fmt.Println(add(1)) // 1 fmt.Println(add(2)) // 3 無名関数: ▶ クロージャ(外部の変数を捕捉する関数) : ▶ 31
  15. 構造体の定義と使用 type Person struct { Name string Age int }

    p1 := Person{"Alice", 30} p2 := Person{Name: "Bob", Age: 25} p3 := Person{Name: "Charlie"} // Ageは0(ゼロ値)で初期化される fmt.Println(p1.Name) // Alice p2.Age = 26 基本的な構造体の定義: ▶ 構造体の初期化: ▶ 構造体のフィールドへのアクセス: ▶ 34
  16. 構造体のメソッド func (p Person) Greet() string { return fmt.Sprintf("Hello, my

    name is %s and I'm %d years old", p.Name, p.Age) } p := Person{"Dave", 30} fmt.Println(p.Greet()) // "Hello, my name is Dave and I'm 30 years old" メソッドの定義: ▶ メソッドの使用: ▶ 35
  17. オブジェクト指向プログラミングの簡略化 type Employee struct { Person```go JobTitle string } e

    := Employee{Person: Person{"Eve", 28}, JobTitle: "Engineer"} fmt.Println(e.Name) // Eve(Personのフィールドに直接アクセス可能) fmt.Println(e.Greet()) // PersonのGreetメソッドも使用可能 Goは継承を使わずにコンポジションを推奨 ▶ 埋め込みを使用した構造体の拡張: ▶ 36
  18. インターフェースの概念 type Shapes interface { Area() float64 Perimeter() float64 }

    type Rectangle struct { Width, Height float64 } func (r Rectangle) Area() float64 { return r.Width * r.Height } func (r Rectangle) Perimeter() float64 { return 2 * (r.Width + r.Height) } // RectangleはShapesインターフェースを実装していることになる インターフェースの定義: ▶ インターフェースの実装(暗黙的) : ▶ 37
  19. ダックタイピング type Quacker interface { Quack() } type Duck struct{}

    func (d Duck) Quack() { fmt.Println("Quack!") } type Person struct{} func (p Person) Quack() { fmt.Println("The person imitates a duck.") } func MakeItQuack(q Quacker) { q.Quack() } MakeItQuack(Duck{}) // 出力: Quack! MakeItQuack(Person{}) // 出力: The person imitates a duck. Goのインターフェースは暗黙的に実装される ▶ 構造体がインターフェースで定義されたメソッドをすべて持っていれば、そのインターフェースを実装していることにな る ▶ 例: ▶ 38
  20. 空インターフェース func PrintAnything(v interface{}) { fmt.Printf("Value: %v, Type: %T\n", v,

    v) } PrintAnything(42) // 出力: Value: 42, Type: int PrintAnything("Hello") // 出力: Value: Hello, Type: string PrintAnything(true) // 出力: Value: true, Type: bool interface{} は任意の型を表す ▶ 動的型付けが必要な場合に使用 ▶ 例: ▶ 39
  21. Goroutineの基本 func sayHello() { fmt.Println("Hello, Gopher!") } func main() {

    go sayHello() time.Sleep(time.Second) // メインゴルーチンが終了しないよう少し待つ } Goroutineは軽量スレッド ▶ 関数の前に go キーワードを付けて起動 ▶ 例: ▶ 42
  22. バッファ付きチャネル ch <- 1 ch <- 2 ch <- 3

    // ch <- 4 // ここでブロック(バッファが満杯) 一定数のデータを保持できるチャネル ▶ 作成: ch := make(chan int, 3) // バッファサイズ3のint型チャネル ▶ バッファが埋まるまで送信はブロックされない ▶ バッファが空の場合、受信はブロックされる ▶ 例: ▶ 45
  23. select文 select { case v1 := <-ch1: fmt.Println("Received from ch1:",

    v1) case v2 := <-ch2: fmt.Println("Received from ch2:", v2) case ch3 <- 42: fmt.Println("Sent to ch3") default: fmt.Println("No channel operations ready") } 複数のチャネル操作を待機 ▶ 準備ができた操作から実行 ▶ 例: ▶ 46
  24. デッドロック検出 func main() { ch := make(chan int) ch <-

    1 // デッドロック:受信側がいないのでブロック fmt.Println(<-ch) } 実行結果: fatal error: all goroutines are asleep - deadlock! Goランタイムは自動的にデッドロックを検出 ▶ すべてのGoroutineがブロックされた状態で検出 ▶ 例: ▶ 48
  25. エラー処理の基本 func divide(a, b float64) (float64, error) { if b

    == 0 { return 0, errors.New("division by zero") } return a / b, nil } result, err := divide(10, 0) if err != nil { fmt.Println("Error:", err) } else { fmt.Println("Result:", result) } Goでは error 型を使用してエラーを表現 ▶ 関数は通常、最後の戻り値としてエラーを返す ▶ 例: ▶ 51
  26. カスタムエラーの作成 type MyError struct { Code int Message string }

    func (e *MyError) Error() string { return fmt.Sprintf("エラーコード %d: %s", e.Code, e.Message) } errors.New 関数を使用: err := errors.New("カスタムエラーメッセージ") ▶ fmt.Errorf を使用(フォーマット付き) : err := fmt.Errorf("値%dは不正です", value) ▶ カスタムエラー型の定義: ▶ 52
  27. エラーのラッピング(Go 1.13以降) originalErr := errors.New("原因エラー") wrappedErr := fmt.Errorf("追加コンテキスト: %w", originalErr)

    if errors.Is(wrappedErr, originalErr) { fmt.Println("originalErrが含まれています") } エラーに追加情報を付加して伝播 ▶ fmt.Errorf と %w 動詞を使用: ▶ ラップされたエラーの取り出し: ▶ 53
  28. パニックとリカバリ func mayPanic() { panic("予期せぬエラー") } func main() { defer

    func() { if r := recover(); r != nil { fmt.Println("Recovered from panic:", r) } }() mayPanic() fmt.Println("この行は実行されません") } パニック:プログラムの実行を中断し、スタックをアンワインド ▶ リカバリ:パニックから回復し、通常の実行を再開 ▶ 例: ▶ 54
  29. パッケージの概念 package mypackage func MyFunction() { // 実装 } 関連する機能をグループ化するための仕組み

    ▶ 各 .go ファイルは package 宣言で始まる ▶ 同じディレクトリ内のファイルは同じパッケージに属する ▶ 例: ▶ 58
  30. パッケージの可視性 package mypackage var ExportedVar = 42 // 公開 var

    unexportedVar = "hello" // 非公開 func ExportedFunc() {} // 公開 func unexportedFunc() {} // 非公開 大文字で始まる識別子:エクスポートされる(公開) ▶ 小文字で始まる識別子:パッケージ内部でのみ使用可能(非公開) ▶ 例: ▶ 59
  31. Go Modulesの基本 Go 1.11以降の依存関係管理システム ▶ プロジェクトごとに異なるバージョンの依存関係を管理可能 ▶ 主要コマンド: ▶ go

    mod init : 新しいモジュールの初期化 - go get : 依存関係の追加・更新 - go mod tidy : 使用されていない依存関係の削除 - go.mod ファイル:モジュール定義と依存関係を記述 ▶ 60
  32. Go Modulesの使用例 go mod init github.com/username/project go get github.com/some/dependency module

    github.com/username/project go 1.16 require ( github.com/some/dependency v1.2.3 ) 1. モジュールの初期化: 2. 依存関係の追加: 3. go.mod ファイルの例: 61
  33. 標準ライブラリの活用 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, World!")

    }) http.ListenAndServe(":8080", nil) Goは豊富な標準ライブラリを提供 ▶ 主要な標準パッケージ: ▶ fmt : フォーマット済み I/O - io : 基本的な I/O インターフェース - os : OS機能へのインターフェース - net/http : HTTPクライアントとサーバー - encoding/json : JSON処理 - time : 時間と日付の操作 - 例:HTTPサーバー ▶ 62
  34. クロスプラットフォームサポート GOOS=windows GOARCH=amd64 go build main.go GOOS=linux GOARCH=amd64 go build

    main.go GOOS=darwin GOARCH=amd64 go build main.go // +build windows package main import "fmt" func main() { fmt.Println("This is a Windows-specific code") } Goは複数のプラットフォームをネイティブにサポート ▶ 単一のコードベースから異なるOS用のバイナリを生成可能 ▶ クロスコンパイルの例: ▶ プラットフォーム固有のコードは条件付きコンパイルで制御可能: ▶ 63
  35. テストの基本 // main.go func Add(a, b int) int { return

    a + b } // main_test.go package main import "testing" func TestAdd(t *testing.T) { result := Add(2, 3) if result != 5 { t.Errorf("Add(2, 3) = %d; want 5", result) } } テストファイルは _test.go で終わる名前を持つ ▶ テスト関数は Test で始まる ▶ testing パッケージを使用 ▶ 66
  36. テーブル駆動テスト func TestAdd(t *testing.T) { tests := []struct { a,

    b, want int }{ {2, 3, 5}, {0, 0, 0},{-1, 1, 0}, } for _, tt := range tests { if got := Add(tt.a, tt.b); got != tt.want { t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, got, tt.want) } } } 複数のテストケースを効率的に記述 ▶ データ構造を使用してテストケースを定義 ▶ 67
  37. ベンチマークテスト func BenchmarkAdd(b *testing.B) { for i := 0; i

    < b.N; i++ { Add(2, 3) } } 実行: go test -bench=. パフォーマンス測定のためのテスト ▶ Benchmark で始まる関数名 ▶ testing.B を使用 ▶ 68
  38. カバレッジテスト go test -cover 詳細なカバレッジレポート: go test -coverprofile=coverage.out go tool

    cover -html=coverage.out コードカバレッジを測定 ▶ -cover フラグを使用 ▶ 69
  39. モックとスタブ type DataStore interface { GetUser(id int) (string, error) }

    type MockDataStore struct{} func (m *MockDataStore) GetUser(id int) (string, error) { return "Mock User", nil } func TestUsingMock(t *testing.T) { mock := &MockDataStore{} // mockを使用してテスト } 外部依存をシミュレートするためのテクニック ▶ インターフェースを活用 ▶ 70
  40. 標準HTTPサーバー package main import ( "fmt" "net/http" ) func handler(w

    http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:]) } func main() { http.HandleFunc("/", handler) http.ListenAndServe(":8080", nil) } net/http パッケージを使用 ▶ 基本的なHTTPサーバーの例: ▶ 73
  41. ルーティング http.HandleFunc("/", homeHandler) http.HandleFunc("/about", aboutHandler) r := mux.NewRouter() r.HandleFunc("/users/{id:[0-9]+}", getUserHandler).Methods("GET")

    基本的なルーティング: ▶ Gorillaムックス(サードパーティライブラリ)を使用した高度なルーティング: ▶ 74
  42. ミドルウェア func loggingMiddleware(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r

    *http.Request) { log.Printf("Received request: %s %s", r.Method, r.URL.Path) next.ServeHTTP(w, r) } } http.HandleFunc("/", loggingMiddleware(homeHandler)) HTTPハンドラーをラップして追加機能を提供 ▶ 75
  43. データベース接続 import ( "database/sql" _ "github.com/go-sql-driver/mysql" ) db, err :=

    sql.Open("mysql", "user:password@/dbname") if err != nil { log.Fatal(err) } defer db.Close() rows, err := db.Query("SELECT * FROM users") // rows の処理 database/sql パッケージを使用 ▶ 様々なデータベースドライバーをサポート ▶ 77
  44. RESTful API開発 func userHandler(w http.ResponseWriter, r *http.Request) { user :=

    User{Name: "Alice", Age: 30} w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(user) } var user User err := json.NewDecoder(r.Body).Decode(&user) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } JSONレスポンスの生成: ▶ リクエストのパース: ▶ 78