20210915のGoに関する記事は6件です。

Go言語のechoフレームワークを使用してAPIサーバーを立てる方法(入門)

Go言語にて、echoを使用してAPIサーバーを立てる方法を解説します インストール 以下のコマンドでインストール go get github.com/labstack/echo/v4 GetのAPIを実装する GetのAPIを実装したmain.goを作成 main.go package main import ( "net/http" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" ) func main() { // echoインスタンスを生成 e := echo.New() // Middleware // httpリクエストの情報をログに表示 e.Use(middleware.Logger()) // パニックを回復し、スタックトレースを表示 e.Use(middleware.Recover()) // ルーティング e.GET("/", getSample) // サーバーをスタートさせる // ポート番号は引数で指定できる e.Logger.Fatal(e.Start(":8080")) } // Get API func getSample(c echo.Context) error { return c.String(http.StatusOK, "Get!") } 起動 go run main.go ____ __ / __/___/ / ___ / _// __/ _ \/ _ \ /___/\__/_//_/\___/ v4.5.0 High performance, minimalist Go web framework https://echo.labstack.com ____________________________________O/_______ O\ ⇨ http server started on [::]:8080 curlで確認 curl 'http://localhost:8080/' 以下がレスポンスとして返却されたらOK Get! PostのAPIを実装する Postの実装は以下の記述を追加 // mainメソッドのルーティングに追加 e.POST("/post", postSample) // mainメソッド外に追加 // Post API func postSample(c echo.Context) error { // Postの処理 return c.String(http.StatusOK, "Post!") } curlで確認 curl -X POST 'http://localhost:8080/post' 以下がレスポンスとして返却されたらOK Post! パラメーターを受け取る方法 URLパラメーターを受け取る場合は Param を使う // mainメソッドのルーティングききに追加 e.POST("/post/:id", postSample) // mainメソッド外に追加 func postSample(c echo.Context) error { id, _ := strconv.Atoi(c.Param("id")) msg := fmt.Sprintf("url param %v", id) return c.String(http.StatusOK, msg) } また、クエリパラメーターを受け取る場合は QueryParam を使う hoge := c.QueryParam("hoge") curlで確認。レスポンスにURLパラメーターで渡したIDが確認できる $ curl -X POST 'http://localhost:8080/post/1' url param 1 リクエストボディを受け取る方法 ボディとして渡されるjsonに合わせて構造体を用意して、Bindメソッドを使って受け取る // 受け取るための構造体 type post struct { ID int `json:"id"` Name string `json:"name"` } // mainメソッドのルーティングに追加 e.POST("/post/:id", postSample) // Handler func postSample(c echo.Context) error { p := new(post) if err := c.Bind(p); err != nil { log.Printf("err %v", err.Error()) return c.String(http.StatusInternalServerError, "Error!") } // URLパラメーターはBindで入らない id, err := strconv.Atoi(c.Param("id")) if err != nil { log.Printf("err %v", err.Error()) return c.String(http.StatusInternalServerError, "Error!") } p.ID = id msg := fmt.Sprintf("id: %v, name %v", p.ID, p.Name) return c.String(http.StatusOK, msg) } curlで確認。レスポンスに送信したパラメーターが出力されている $ curl -X POST -H 'Content-Type: application/json' -d '{"Name":"taro"}' localhost:8080/post/1 id: 1, name taro Put, Deleteの場合 Put, Deleteに関しても以下のようにルーティングを定義して関数を追加することで実装可能 e.PUT("/put", putSample) e.DELETE("/delete", deleteSample) レスポンスの返却方法 レスポンスは、return部分にステータスコードと返却する内容を指定する 単純な文字列を返却する場合は、 String を使う return c.String(http.StatusOK, "Get!") JSONを返却したい場合は、 JSON を使う // 構造体 type post struct { ID int `json:"id"` Name string `json:"name"` } // ルーティング(main内) e.GET("/sample", getResponseSample) // Handler func getResponseSample(c echo.Context) error { p := &post{ ID: 1, Name: "taro", } return c.JSON(http.StatusOK, p) } 出典 echo リファレンス https://echo.labstack.com/ labstack/echo https://github.com/labstack/echo
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

OpenAPI等のジェネレータツールによる更新作業の自動化、失敗時の自動ロールバックの実現

OpenAPI等のジェネレータツールによる更新作業の自動化、失敗時の自動ロールバックの実現 こんにちは、 最近はOpenAPIやgRPCであったり、それにまつわるジェネレータツールがとても熱いですね。 新規にジェネレータを走らせるのは何の憂いもなく素晴らしいのですが、 開発が進むにつれて、ディレクトリ構造が追加、変更されたり、中間処理を挟んだりと、素のジェネレータでは対応できない場合があります。 また、複数のジェネレータを使う場合、それぞれのジェネレータのご機嫌を伺わなければならない状況が発生し、そもそも更新作業にはジェネレータを使わないようになる場合も多いと思います。 ジェネレートした結果が意図した結果にならなかった場合、その問題を解決するために、いちいちGit操作を行ったり、例えば、ある段階のcommitを取り消したりrebaseしたりする操作を行うとそれだけで丸1日が潰れてしまう経験をお持ちの方もいるのではないでしょうか。 今回は、ジェネレータをもっと効率的に使うために、ジェネレート作業の自動化と適切なロールバックを行うことができるスクリプトを作ってみました。 今回の検証環境では以下のようになっています。 ツールや言語等 macOS BigSur 11.2.3 Git (git version 2.24.3 (Apple Git-128)) Bash (GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin20)) Docker (Docker version 20.10.7, build f0df350) OpenAPI (Version 3.0.3) openapitools/openapi-generator-cli Go (go version go1.16.3 darwin/amd64) 前提条件 まず、前提として、Git管理されているプロジェクトのホームディレクトリ等の上でスクリプトを走らせる必要があります。 また、今回はOpenAPIのopenapitools/openapi-generator-cliにおけるジェネレート作業を取り扱うので、その他のツールでは、reset_* generate_* replace_* の内容に関して読み替えを行う必要があります。 また、チケット単位で考えるとき、人が行う作業とジェネレート作業を完全に切り分ける必要があります。 ただし、作業を分担する上で、複数人がジェネレート作業を行わなければならない場合は、そのチケットに取り掛かる一番初めにこのジェネレート作業を行うという制約を設定する必要があります。 つまり、要件定義の更新作業を別チケットで対応し(主にopenapi.ymlの修正)所定のブランチにマージします。 その後、実装の修正更新作業は別チケットで対応します。 その実装作業を始める一番最初にこのスクリプトを走らせるという前提です。 スクリプト解説 今回はBashを使うのでシバン等を次のように設定します。 #!/bin/bash set -eux また、ロールバックを制御するためにerrtraceを設定します。 set -o errtrace 今回はロールバックにGitを使います。 また、失敗した段階で自動でロールバックを行いたいので、trapを設定します。 function trap_common() { trap "git stash && git clean -fd ; echo Failed ;" 2 trap "git stash && git clean -fd ; echo Failed ; exit 1" ERR } trapではスクリプトのステータスコードによって処理を分岐できるので、今回はエラー時と中断時にロールバックが走るように設定します。 次にリセット作業を行います。 更新する際にリセットを行わなければならないと思いますが、こちらはあらかじめ予約語を設定しておいて、ツールが出力する一定の法則に基づいたファイル名を利用してワイルドカードを駆使してリセットを行うというのが妥当だと思います。 次の例ではmodelとapiのリセットを行なっています。 function reset_model_phase() { git rm "${SET_PATH}"/web-api/go/model/model_* mkdir "${SET_PATH}"/web-api/go/model } function reset_api_phase() { rm "${SET_PATH}"/web-api/go/api/api_* rm "${SET_PATH}"/web-api/go/api/routers.go } 今回はmodelとapiに対するディレクトリ構造を変更しているので対象のディレクトリの対象のファイルをワイルドカードを使って削除します。 心配な方はこの作業の一つ上でバックアップ処理を挟んでも良いかもしれません。 次にリセットができれば、ジェネレートを行いましょう。 function genarate_phase() { docker run --rm -v "${SET_PATH}":/app openapitools/openapi-generator-cli generate -i /app/api/openapi.yml -g go-gin-server -o /app/web-api rm "${SET_PATH}"/web-api/Dockerfile } この際、ジェネレート時に作成される不要なファイル等があればこの関数内で削除します。つまり、generate時に生成されるファイル自体に改変を行いたい場合はこの関数内で適応するべきということです。 次に新しいディレクトリ構造に対応する作業を行います function replace_api_model() { mv "${SET_PATH}"/web-api/go/api_*.go "${SET_PATH}"/web-api/go/routers.go "${SET_PATH}"/web-api/go/api mv "${SET_PATH}"/web-api/go/model_* "${SET_PATH}"/web-api/go/model } 今回はmodelとapiの場所を追加しそれに則り変更したいので、mvコマンドでリプレースを行います。 次に、ジェネレートが行なった変更と手動で行う修正作業とを完全に切り分けるために自動でcommitを生成します。 まずはadd作業です。 function git_add_phase() { git add "${SET_PATH}"/web-api/.openapi-generator/FILES "${SET_PATH}"/web-api/api/openapi.yaml "${SET_PATH}"/web-api/go/README.md "${SET_PATH}"/web-api/go/model/model_* "${SET_PATH}"/web-api/go/api/routers.go git checkout "${SET_PATH}"/web-api/main.go git add -p git diff --cached } この際、ジェネレート作業において強制的に変更されてしまう内容を無視したいファイルがある場合にはcheckoutを個別に行なって変更をなかったことにします。 またaddのpオプションで更新するべきファイルとそうでないファイルをインタラクティブに判断します。 最後にdiffでステージ上の変更内容を改めて確認します。 この段階で正しくない更新が発見されたらその箇所の差分等をメモしておいて、処理をctl+cで中断させましょう。 先ほど設定した標準のロールバック処理が走ります。 問題がなければ次に、commitを行います。 commitまでする必要は無いのではと思う方もおられるかもしれませんが、ジェネレータの更新と人が行う更新を完全に切り分ける方がクリーンで効率的なので、commitを自動で行うようにしています。 ここでロールバック処理をカスタマイズします、そもそもスクリプトが勝手にcommitを行うのは大変危険なのでこの処理もロールバックは必須です。 ここではerrtraceを別にセットします。 set +o errtrace また、カスタマイズされたロールバックを元に戻すには再度errtraceを次のように設定しましょう。 set -o errtrace commitを行います。 この関数内でtrapを設定し直し、ロールバック処理のカスタマイズを行います。 function commit_phase() { git status trap "git stash && git clean -fd && git reset --hard HEAD^ ; echo Failed ; exit 1" ERR git commit -m "generate code from openapi.yml" } 次に新規にジェネレータによって生成されたファイルに関してはGit上ではトラッキングされていないので、そのためのcommitを行います。 function new_file_commit_phase() { git stash CHECK_UNTRACKED="$(git status -s)" ; readonly CHECK_UNTRACKED if [[ "${CHECK_UNTRACKED}" = "??"* ]]; then git add "${SET_PATH}"/web-api/go/api/api_* trap "git stash && git clean -fd && git reset --hard HEAD^ ; echo Failed ; exit 1" ERR git commit -m "generate new api_* files from openapi.yml" else echo "Skip this phase" fi } まず、すでにcommit済みなのでstashを行いトラッキングされていないファイルのみを作業中のステージに残るようにします。 次に、statusでトラッキングされていないファイルが存在するかどうかを判定します。 s オプションでstatusを省略表記で確認できます。 この際、「??」が存在する時点でトラッキングされていないファイルが存在することになるので、それをフラグとして条件分岐を行います。 条件を満たす場合にはステージにaddしcommitを行います。 条件を満たさない場合にはスキップします。 最後にmain関数で標準ロールバックとカスタマイズロールバックを制御します。 この関数を追加する場合は先ほど時点でのerrtraceの設定は必要ありません。 function main() { trap_common reset_model_phase reset_api_phase genarate_phase replace_api_model git_add_phase set +o errtrace commit_phase new_file_commit_phase set -o errtrace } スクリプトの全体像は次のようになります。 #!/bin/bash set -eux set -o errtrace SET_PATH=$(pwd) ; readonly SET_PATH function trap_common() { trap "git stash && git clean -fd ; echo Failed ;" 2 trap "git stash && git clean -fd ; echo Failed ; exit 1" ERR } function reset_model_phase() { git rm "${SET_PATH}"/web-api/go/model/model_* mkdir "${SET_PATH}"/web-api/go/model } function reset_api_phase() { rm "${SET_PATH}"/web-api/go/api/api_* rm "${SET_PATH}"/web-api/go/api/routers.go } function genarate_phase() { docker run --rm -v "${SET_PATH}":/app openapitools/openapi-generator-cli generate -i /app/api/openapi.yml -g go-gin-server -o /app/web-api rm "${SET_PATH}"/web-api/Dockerfile } function replace_api_model() { mv "${SET_PATH}"/web-api/go/api_*.go "${SET_PATH}"/web-api/go/routers.go "${SET_PATH}"/web-api/go/api mv "${SET_PATH}"/web-api/go/model_* "${SET_PATH}"/web-api/go/model } function git_add_phase() { git add "${SET_PATH}"/web-api/.openapi-generator/FILES "${SET_PATH}"/web-api/api/openapi.yaml "${SET_PATH}"/web-api/go/README.md "${SET_PATH}"/web-api/go/model/model_* "${SET_PATH}"/web-api/go/api/routers.go git checkout "${SET_PATH}"/web-api/main.go git add -p git diff --cached } function commit_phase() { git status trap "git stash && git clean -fd && git reset --hard HEAD^ ; echo Failed ; exit 1" ERR git commit -m "generate code from openapi.yml" } function new_file_commit_phase() { git stash CHECK_UNTRACKED="$(git status -s)" ; readonly CHECK_UNTRACKED if [[ "${CHECK_UNTRACKED}" = "??"* ]]; then git add "${SET_PATH}"/web-api/go/api/api_* trap "git stash && git clean -fd && git reset --hard HEAD^ ; echo Failed ; exit 1" ERR git commit -m "generate new api_* files from openapi.yml" else echo "Skip this phase" fi } function main() { trap_common reset_model_phase reset_api_phase genarate_phase replace_api_model git_add_phase set +o errtrace commit_phase new_file_commit_phase set -o errtrace } main echo "done" 最後に 今までは属人的にジェネレート作業は〇〇さんにお願いします、という感じで進んでいました。 仕様が変更されるたびにそれにまつわるジェネレート作業が発生する状況の場合、ジェネレート作業を終えた後に純粋にマージしたくても、マージ条件をクリアできない場合が多々あると思います。 その際、〇〇さんの本来の作業ではないロジックの修正までもマージ条件の制約上、行わなくてはならない状況が発生することが容易に予想できます。 私自身も〇〇さん状況になってしまった経験があります。 この経験があって今回このようなスクリプトを書きました。 今回の内容で、ジェネレート作業そのものをスクリプト化しそれを走らせるだけで、誰でもジェネレート作業を行うことができるようになります。 これで、作業を分担できるようになるので、プロジェクトの開発効率が一気に上がるのでは無いでしょうか。 今回は紹介していませんが、これに加えてさらにDockerでスクリプトを走らせるようにするとさらに良いですね。 今回はBashで自動化を実現したので、汎用性が高いと思います、ジェネレート作業に関係なく、さまざまな場面で応用できると思います。 今後git_add_phaseに関しては、改良の余地があると思うので、引き続き最適化していきたいと思います。 参考文献 「OpenAPI Specification」https://swagger.io/specification/ 「APIのコードを自動生成させたいだけならgRPCでなくてもよくない?」https://www.m3tech.blog/entry/2019/08/15/110000 「bashのtrap(ERR)が関数内に継承されないわけがない」https://qiita.com/kurapooh/items/67687ae3c4540d4b7d40 「シグナルとtrapコマンド」https://shellscript.sunone.me/signal_and_trap.html
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker とVisual Studio Code を使った Go (Golang) 開発環境構築

Golang の開発環境を Docker と Visual Studio Code で約 3 分で構築する手順を解説します Docker と Visual Studio Code を組み合わせて開発環境を準備する利点については 次の記事を参照してください: 【Docker】【Visual Studio Code】 PC に言語をインストールせずにプログラム開発しよう | ultra code 開発のためのエディターとして Visual Studio Code を利用する利点については 次の記事を参照してください: ファイルやプログラムの編集には Visual Studio Code を使おう | ultra code この手順で開発環境が構築できる理屈については次の記事を参照してください: 【Docker】【Visual Studio Code】 PC に言語をインストールせずにプログラム開発しよう | ultra code あらかじめインストールしておくアプリケーション Docker Desktop Visual Studio Code Remote Development 拡張機能 Golang のインストールは必要ありません 手順 手順内の解説はなるべく省いており、詳細の解説はすべての手順の後に用意してあります 1. Docker Compose のためのファイル準備 プロジェクトフォルダーを新規作成、Visual Studio Code で開き、次の 2 つのファイルを新規作成します: project/ +---Dockerfile +---docker-compose.yml Dockerfile FROM golang:1.17.0-bullseye # Visual Studio Code Remote Development 拡張機能がデフォルトで開くディレクトリーであるため WORKDIR /workspace # 2021-06-10 時点で Visual Studio Code でコードのフォーマットや Lint などの支援を受けるのに必要なモジュール # モジュール未インストール時に Visual Studio Code を開き、次のコマンドで一覧表示されたものです: # Ctrl + Shift + P -> Go: Install/Update Tools RUN go get github.com/uudashr/gopkgs/v2/cmd/gopkgs RUN go get github.com/ramya-rao-a/go-outline RUN go get github.com/cweill/gotests/... RUN go get github.com/fatih/gomodifytags RUN go get github.com/josharian/impl RUN go get github.com/haya14busa/goplay/cmd/goplay RUN go get github.com/go-delve/delve/cmd/dlv # div-dap のインストール方法は次のドキュメントを参考にしました: # https://github.com/golang/vscode-go/blob/v0.26.0/docs/dlv-dap.md#updating-dlv-dap RUN GOBIN=/tmp/ go get github.com/go-delve/delve/cmd/dlv@master \ && mv /tmp/dlv $GOPATH/bin/dlv-dap RUN go get github.com/golangci/golangci-lint/cmd/golangci-lint RUN go get golang.org/x/tools/gopls docker-compose.yml version: "3.8" services: golang: build: . image: yourrepository/golang:development 2. Developing inside a Container のための設定ファイルの追加 Visual Studio Code の画面左下のステータスバーの項目 (リモートクィックアクセス) をクリック -> [Remote-Containers: Add Development Container Configuration Files…] をクリック: すると、どのように設定を作成するかを尋ねるメニューが表示されるので、 [From ‘docker-compose.yml’] をクリック: すると次のファイルが追加されます: project/ +---.devcontainer/ +---devcontainer.json +---docker-compose.yml 3. 拡張機能や Lint の設定を追加 .devcontainer/devcontainer.json に設定を追加します: .devcontainer/devcontainer.json - "settings": {}, + "settings": { + "go.lintTool": "golangci-lint", + "go.lintFlags": [ + "--fast" + ] + }, // ~~~ - "extensions": [] + "extensions": [ + "golang.go" + ] コピー & ペースト用: "settings": { "go.lintTool": "golangci-lint", "go.lintFlags": [ "--fast" ] }, "extensions": [ "golang.go" ] 参考: Integrations | golangci-lint Go with Visual Studio Code 4. コンテナーを起動して Visual Studio Code で開く Visual Studio Code の画面左下のステータスバーの項目 (リモートクィックアクセス) をクリック -> [Reopen in Container] をクリック 5. Golang プロジェクトの初期化 ターミナルを開き、次のようにコマンド実行: go mod init <repository path> 例: go mod init github.com/yukihiko-shinoda/hello-world-golang ※ リポジトリーのパスは後から変えることもできます すると、ファイル: go.mod が作成されます 6. 利用することがわかっているパッケージを依存関係としてファイル: go.mod に追加 例: AWS SDK (https://github.com/aws/aws-sdk-go-v2) の場合: go get -d github.com/aws/aws-sdk-go-v2 ※ または、コードに import 文を書いてから、   コマンド: go mod tidy でファイル: go.mod に反映させることもできます 7. コーディング開始 例: ファイル hello_world.go を作成: hello_world.go package main import "fmt" func main() { fmt.Println("hello world") } 直接実行して動作確認: go run hello_world.go 次のコマンドで、main パッケージの main() を実行可能: go run . 参考: Go by Example: Hello World 解説 Docker と Visual Studio Code による開発環境構築の基本的な理屈については 次の記事を参照してください: 【Docker】【Visual Studio Code】 PC に言語をインストールせずにプログラム開発しよう | ultra code ここでは Golang 特有の内容について解説します Dockerfile について FROM golang:<tag> Golang は公式イメージが提供されています Golang 以外に必要なツールが特にない場合はこのイメージを使うと良いでしょう: Golang - Official Image | Docker Hub タグの意味なども上記 Docker Hub の [Description] タブに記載されていますので さらっと確認しておきましょう RUN go get <package> これらのモジュールを環境にインストールしないと Visual Studio Code で Golang のコードフォーマットや Lint などの支援を受けることができません ちなみに、インストールしなかった場合、 Visual Studio Code がダイアログでインストールを促してくれます しかし、Dockerfile の RUN 命令を使わずにインストールした場合は 環境を再構築することになった時、 必ずこれらのモジュールをインストールし直す時間を浪費することになります Dockerfile にインストールするよう記載しておいた方が 環境を再構築することになった際も時間が節約できる可能性が高くなるのでおすすめです (Docker は構築の結果をキャッシュするため) 参考: Best practices for writing Dockerfiles | Docker Documentation
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Go (Golang) Docker と VisualStudioCode による開発環境構築

Golang の開発環境を Docker と Visual Studio Code で約 3 分で構築する手順を解説します Docker と Visual Studio Code を組み合わせて開発環境を準備する利点については 次の記事を参照してください: 【Docker】【Visual Studio Code】 PC に言語をインストールせずにプログラム開発しよう | ultra code 開発のためのエディターとして Visual Studio Code を利用する利点については 次の記事を参照してください: ファイルやプログラムの編集には Visual Studio Code を使おう | ultra code この手順で開発環境が構築できる理屈については次の記事を参照してください: 【Docker】【Visual Studio Code】 PC に言語をインストールせずにプログラム開発しよう | ultra code あらかじめインストールしておくアプリケーション Docker Desktop Visual Studio Code Remote Development 拡張機能 Golang のインストールは必要ありません 手順 手順内の解説はなるべく省いており、詳細の解説はすべての手順の後に用意してあります 1. Docker Compose のためのファイル準備 プロジェクトフォルダーを新規作成、Visual Studio Code で開き、次の 2 つのファイルを新規作成します: /project +---Dockerfile +---docker-compose.yml Dockerfile FROM golang:1.17.0-bullseye # Visual Studio Code Remote Development 拡張機能がデフォルトで開くディレクトリーであるため WORKDIR /workspace # 2021-06-10 時点で Visual Studio Code でコードのフォーマットや Lint などの支援を受けるのに必要なモジュール # モジュール未インストール時に Visual Studio Code を開き、次のコマンドで一覧表示されたものです: # Ctrl + Shift + P -> Go: Install/Update Tools RUN go get github.com/uudashr/gopkgs/v2/cmd/gopkgs RUN go get github.com/ramya-rao-a/go-outline RUN go get github.com/cweill/gotests/... RUN go get github.com/fatih/gomodifytags RUN go get github.com/josharian/impl RUN go get github.com/haya14busa/goplay/cmd/goplay RUN go get github.com/go-delve/delve/cmd/dlv # div-dap のインストール方法は次のドキュメントを参考にしました: # https://github.com/golang/vscode-go/blob/v0.26.0/docs/dlv-dap.md#updating-dlv-dap RUN GOBIN=/tmp/ go get github.com/go-delve/delve/cmd/dlv@master \ && mv /tmp/dlv $GOPATH/bin/dlv-dap RUN go get github.com/golangci/golangci-lint/cmd/golangci-lint RUN go get golang.org/x/tools/gopls docker-compose.yml version: "3.8" services: golang: build: . image: futureys/golang:development 2. Developing inside a Container のための設定ファイルの追加 Visual Studio Code の画面左下のステータスバーの項目 (リモートクィックアクセス) をクリック -> [Remote-Containers: Add Development Container Configuration Files…] をクリック: すると、どのように設定を作成するかを尋ねるメニューが表示されるので、 [From ‘docker-compose.yml’] をクリック: すると次のファイルが追加されます: /project +---.devcontainer +---devcontainer.json +---docker-compose.yml 3. 拡張機能や Lint の設定を追加 .devcontainer/devcontainer.json に設定を追加します: .devcontainer/devcontainer.json - "settings": {}, + "settings": { + "go.lintTool": "golangci-lint", + "go.lintFlags": [ + "--fast" + ] + }, // ~~~ - "extensions": [] + "extensions": [ + "golang.go" + ] 参考: Integrations | golangci-lint Go with Visual Studio Code 4. コンテナーを起動して Visual Studio Code で開く Visual Studio Code の画面左下のステータスバーの項目 (リモートクィックアクセス) をクリック -> [Reopen in Container] をクリック 5. Golang プロジェクトの初期化 ターミナルを開き、次のようにコマンド実行: go mod init <repository path> 例: go mod init github.com/yukihiko-shinoda/hello-world-golang ※ リポジトリーのパスは後から変えることもできます すると、ファイル: go.mod が作成されます 6. 利用することがわかっているパッケージを依存関係としてファイル: go.mod に追加 例: AWS SDK (https://github.com/aws/aws-sdk-go-v2) の場合: go get -d github.com/aws/aws-sdk-go-v2 ※ または、コードに import 文を書いてから、   コマンド: go mod tidy でファイル: go.mod に反映させることもできます 7. コーディング開始 例: hello_world.go package main import "fmt" func main() { fmt.Println("hello world") } hello_world.go ファイルを作成 go run hello_world.go で直接実行して動作確認 go run . で main パッケージの main() を実行可能 参考: Go by Example: Hello World 解説 Docker と Visual Studio Code による開発環境構築の基本的な理屈については 次の記事を参照してください: 【Docker】【Visual Studio Code】 PC に言語をインストールせずにプログラム開発しよう | ultra code ここでは Golang 特有の内容について解説します Dockerfile について FROM golang:<tag> Golang は公式イメージが提供されています Golang 以外に必要なツールが特にない場合はこのイメージを使うと良いでしょう: Golang - Official Image | Docker Hub タグの意味なども上記 Docker Hub の [Description] タブに記載されていますので さらっと確認しておきましょう RUN go get <package> これらのモジュールを環境にインストールしないと Visual Studio Code で Golang のコードフォーマットや Lint などの支援を受けることができません ちなみに、インストールしなかった場合、 Visual Studio Code がダイアログでインストールを促してくれます しかし、Dockerfile の RUN 命令を使わずにインストールした場合は 環境を再構築することになった時、 必ずこれらのモジュールをインストールし直す時間を浪費することになります Dockerfile にインストールするよう記載しておいた方が 環境を再構築することになった際も時間が節約できる可能性が高くなるのでおすすめです (Docker は構築の結果をキャッシュするため) 参考: Best practices for writing Dockerfiles | Docker Documentation
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

deferの即時評価

Go言語の勉強を始めたのですが、deferで引っかかってしまった部分があったのでまとめまてみました。 defer ステートメントは、 defer へ渡した関数の実行を、呼び出し元の関数の終わり(returnする)まで遅延させるものです。 defer へ渡した関数の引数は、すぐに評価されますが、その関数自体は呼び出し元の関数がreturnするまで実行されません。 引用元:A Tour of Go 上記の通りdeferを使うことで、呼び出している関数がreturnするまで処理の実行を遅らせることができます。 例えばファイルを閉じたりチャネルをクローズするのに使われます。 サンプルコード func main() { file, _ := os.Open("./example.txt") defer file.Close() data := make([]byte, 100) file.Read(data) fmt.Println(string(data)) } そして引っかかってしまった部分は func main() { var fruit string = "Orange" defer fmt.Println(fruit) fruit = "Apple" } 結果:Orange Appleが帰ってくると予想していたので、???となってしまいました。 実は引用文の2行目に非常に重要なことが書かれています。 defer へ渡した関数の引数は、すぐに評価されますが、その関数自体は呼び出し元の関数がreturnするまで実行されません。 つまりdeferへ渡した関数の引数は、deferが評価された時点で値が保持されてしまうということです。だからdeferの評価後に変数fruitの値を変更しても、deferでの実行には反映されていなかったのです。 他にもdeferを使ってpanicからrecoverするとき、 panic/recover func main() { defer func() { s := recover() fmt.Println(s,"ok") }() panic("panic!!!") } これだとrecoverできてokが出力されますが、 panic/recover func main() { panic("panic!!!") defer func() { s := recover() fmt.Println(s,"ok") }() } このようにpanicをdeferより前に書いてしまうとそのままプログラムが終了してしまいます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Golang】mapに複数のキーを設定する

個人的に感動的に便利だったので、書いておきます。 コード mapのキーにstructを設定すると出来ます。 複数のキーで一つの値を持っておきたい時に便利です package main import ( "fmt" ) type key struct { key1 string key2 string } func main() { m := map[key]string{ key{ key1: "hoge_key1", key2: "hoge_key2", }: "hoge", } fmt.Println(m) } // 結果:map[{hoge_key1 hoge_key2}:hoge]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む