【Part4】Go言語(golang)の基本とTips

環境

  • Windows 10
  • golang1.18
  • VSCode
  • Docker
masayan
masayan

以下のドキュメントは一読されることをおすすめします。

https://go.dev/doc/effective_go

本シリーズの記事で説明する内容

  1. きほんのき
  2. ファイル、クラス等の命名規則や慣習
  3. 環境構築
  4. モジュールのimport
  5. 変数定義と代入
  6. ポインタ
  7. 配列・スライス
  8. マップ
  9. 繰り返し
  10. 条件分岐
  11. 関数
  12. ジェネリクス
  13. クラスの作り方(正確にはクラスではない)
  14. インターフェース
  15. 単体テスト
  16. フォーマット
  17. その他Tips
masayan
masayan

本記事(part4)では、上記の14.~17.について説明します

インターフェース

  • Csv読み取りのインターフェース例
  • メソッドと返り値の型情報だけを定義する
    package interfaces
    
    type CsvReader interface {
        ReadAll() (record [][]string, err error)
    }
  • Goでは、interfaceに定義した関数を定義していれば暗黙的にそのインタフェースを実装していることになる
  • 以下の実装例では、CsvReaderのReadAll()を実装クラスに定義している
    package classes
    
    import (
        "encoding/csv"
        "log"
        "os"
        "golang.org/x/text/encoding/japanese"
        "golang.org/x/text/transform"
    )
    
    type CsvReaderImpl struct {
        file string
    }
    
    
    func (c *CsvReaderImpl) init(file string) {
        c.file = file
    }
    
    func NewCsvReaderImpl(file string) *CsvReaderImpl {
        c := new(CsvReaderImpl)
        c.init(file)
        return c
    }
    
    func (c CsvReaderImpl) ReadAll() (record [][]string, err error) {
        r := open(c.file)
        re, e := r.ReadAll()
        if e != nil {
            log.Fatal(e)
        }
    
        return re, e
    }
    
    func open(file string) *csv.Reader {
        f, err := os.Open(file)
        if err != nil {
            log.Fatal(err)
        }
    
        return csv.NewReader(transform.NewReader(f, japanese.ShiftJIS.NewDecoder()))
    }
  • 上記のように定義することで、呼び出し側ではinterfaceに実装クラスの値を代入することが可能になっている
  • interfaceに代入できると、interfaceは代入された値に応じて動的に異なるふるまいを行うことが可能になる
    package main
    
    
    import (
        "fmt"
        "mymodule/classes"
        "mymodule/interfaces"
    )
    
    
    func main() {
        file := "sample.csv"
        // interfaceに代入
        var csv_reader interfaces.CsvReader = classes.NewCsvReaderImpl(file)
        records, _ := csv_reader.ReadAll()
        fmt.Println(records) // [[id      name    age] [1 田中    21] [2  佐藤    40]]
    }

単体テスト

  • 標準ライブラリとしてtestingというものが用意されているが、assertが使えない等の理由により、testifyというライブラリのほうが実用的な様子(star数も多い)
  • インストール
    以下のようにインストールを実行すると、go.modファイル内に追加される

    go get github.com/stretchr/testify
  • サンプルのテストファイルは以下の通り
  • テストファイルとして認識させるために、ファイル名はhoge_test.goの形式で、また関数名はTestHoge(){}の形にする必要がある
  • tesifiyをインポートし、assert.Equalで期待する値かどうかチェック
    package tests
    
    
    import (
        "mymodule/recipe"
        "os"
        "testing"
        "github.com/stretchr/testify/assert"
    )
    
    func TestRecipe_レシピを作成できる(t *testing.T) {
        id := 1
        name := "ハンバーグ"
        recipe := recipe.NewRecipe(id, name)
    
        if recipe == nil {
            t.Errorf("failed NewRecipe()")
        }
    
        assert.Equal(t, 1, recipe.Id())
        assert.Equal(t, "ハンバーグ", recipe.Name())
    }

フォーマット

  • gofmtが標準
  • インデントには原則タブを用いる
  • コメント
    • Go には/* */ブロックコメントと //行コメントがあるが、 通常は行コメントを使う

その他Tips

未使用変数のコンパイルエラー回避

  • goでは未使用変数があると、コンパイルエラー(hogehoge is not used)になるが、そのエラー回避方法
    • blank identifier(_)を使用する
  • エディターの設定
    • vscode
      • 便利拡張機能をインストール
      • go modulesの設定
        • 何も設定しないままだとGOPATHモードになり、モジュールのimportがうまくいかない
        • go.modファイルがプロジェクトのディレクトリ内に存在する状態で、setting.jsonに以下を追記し、go modulesを使用する宣言を行うことでgo modulesモードの設定が可能
          { "go.toolsEnvVars": {"GO111MODULE": "on"}, }

以上です。

    Go学習におすすめの書籍

    タイトルとURLをコピーしました