- 1. Go チャネルの基本的な知識
- 2. Goルーチンの基本的な知識
- 3. Finch の内部実装を見てみた。
- 4. Goroutine はじめました
- 5. SQLへの繋ぎ方(mySQL)
- 6. [Golang]Cognito操作
- 7. 【Go言語】翌月末を求める
- 8. io/fs でのエラー解決方法 “cannot load io/fs: malformed module path “io/fs”: missing dot in first path element”
- 9. 個人開発しました
- 10. go-gorm/genの挙動を追いかけてみた
- 11. いくつかの言語で、空白類の挙動
- 12. 【個人用】Go言語チートシート
- 13. Goでマッチングサイトを作りました
- 14. Go標準パッケージtestingを利用したテスト方法
- 15. mockery でモックを作成する方法
- 16. GoでServeHTTPにパラメーターをのっける
- 17. GoでTDD本の多国通貨やってみた
- 18. Golang 新規プロジェクトのセットアップ
- 19. [golang] GormでDISTINCTを使う
- 20. 1億レコードのテーブルを扱ってみた
Go チャネルの基本的な知識
## チャネルとは
GoルーチンとGoルーチンの間でデータの受け渡しをするためのGo特有のデータ構造。
## チャネルの型
チャネルの型はchan データ型のように書く。以下の例はint型のチャネルを作っている。
“`go
var ch chan int
“`## チャネルの特性
チャネルの中に何かしらのデータを入れると、それを取り出してからでないと他のGoルーチンはチャネルに何のデータも入れることができない。またチャネルから何かデータを取り出そうとしたときに空だった場合、箱に何かが入るまでプログラムの実行は中断される。
`←chan`とすると受信専用チャネルになる。
“`go
var ch1 <-chan int ``` `chan←`とすると送信専用チャネルになる。 ```go var ch2 chan<- int ``` 特に指定しないと双方向のチャネルとなる。 ## チャネルのバッファ チャネルはキューの性質を備えるデータ構造。キューは先入先出の性質があり、キューに先に入れられたデータは先に取得される。 バッファはこのキューを格納する領域のこと
Goルーチンの基本的な知識
## Goルーチンとは
スレッドよりも小さいGo特有の処理単位。goではこのGoルーチンを生成し、並行処理を実行できる。ゴルーチンとも言う。
## Goルーチンの使用方法
`go 関数名`の形で実行すればその関数はGoルーチンとなる。
## sync.WaitGroup
Goルーチンは完了しても特に何の通知もなく終了してしまう。
そこで終了を検知する仕組みが必要。それがsync.WaitGroup。
WaitGroupの値に対してWait()を呼ぶと、WaitGroupが0になるまで待ってくれる。
以下のように使う。mainの書き方
“`go
func main() {
var wg sync.WaitGroup
wg.Add(Goルーチンの数)
go Goルーチン(&wg)
wg.Wait()
}
“`関数の書き方
“`go
func 関数(wg *sync.WaitGroup) {
処理
wg.Done()
}
“`### ポイント
– まず最初に`sync.WaitGroup`を`wg`という変数に入れる。
– `wg.Add()`
Finch の内部実装を見てみた。
## 今 話題になっている Finch
https://qiita.com/yoshii0110/items/692018729b5b2f41b9ac
などを見ていただければ分かりますが、Finch は `ローカルマシン上に仮想環境とコンテナランタイム、ビルドツールなど一式を楽〜に導入` できるツールになっています。
そのコードがhttps://github.com/runfinch/finch
にあります。
コードは Go で書かれていて、Cobra(Go の CLIツール)を使って CLIのコマンドラインを作っています。
簡単に言えば バージョン 0.1.0 の名前から分かるように、Cobra で nerdctl や lima を呼び出しているだけの簡潔な内容に見えます。それでは、その内容を見てみましょう。
## Cobra のエントリーポイント
Cobra の説明は、
https://zenn.dev/tama8021/articles/22_0627_go_cobra_cli
を参照してみて下さい。
Cobra のエントリーポイントは、`finch/c
Goroutine はじめました
[外資就活](https://gaishishukatsu.com) のプッシュ通知処理を Go にリプレースする際に、Goroutine を利用して配信を並行処理するようにしたため、その実装を紹介します。
手探りで実装したため、Goroutine の同時実行数の制御などの考慮はできていなかったりしますが、実装して運用するに至ることはできたので備忘録も兼ねた記事となります。# FCM を利用してプッシュ通知配信
最大で20,000件の配信を行う必要があります。
なるべく一括で配信して FCM へのリクエスト数を減らしたかったため、 [500件のメッセージを一括送信](https://firebase.google.com/docs/cloud-messaging/send-message#send-a-batch-of-messages) をする API を利用しました。
また500件の一括配信を `Goroutine` を利用して並行処理しました。## 実現したい事
– Goroutine を利用した並行処理
– 送信に失敗した FCM トークンの削除
– エラーハンドリング
SQLへの繋ぎ方(mySQL)
## やること
Dockerでdbサーバを立てて、そこにアプリケーション上からアクセスする### Dockerでdbサーバを立てる
今回はMySQLを使用(理由はなんとなく)
“`yml:docker-compose.yml
version: ‘3’services:
db:
image: mysql:5.7
environment:
– MYSQL_DATABASE=sample_db
– MYSQL_ROOT_PASSWORD=password
command: >
–character-set-server=utf8mb4
–collation-server=utf8mb4_general_ci
ports:
– 3306:3306
“`
と記述した。
その後、この`docker-compose.yml`があるディレクトリで、
“`
$ docker-compose up -d
“`
を実行して、コンテナを起動する。
コンテナが起動できているかどうか確認するには、
`
[Golang]Cognito操作
## 注意
細かいエラー処理などはしていないのであくまでも参考程度にしてください。
ほとんどなぐり書きなので使う前にコードを整えてから使ってください。
## 共通の環境引数
– export CLIENTSECRET=
– export CLIENTID=
– export USERERPOOlID=##ライブラリの全体像
![Screenshot 2022-11-29 at 02-27-20 cognitoauth – Go Documentation Server.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681799/7122c124-5a23-3fc8-ae88-e3ee0948195e.png)
## ライブラリ
“`golang:cognitoauth.go
package cognitoauth
import (
“crypto/hmac”
“crypto/sha256”
“encoding/base64”
“fmt”
“os”“github
【Go言語】翌月末を求める
Go言語で翌月末を求める方法について記載してみました。
# 単純なAddDateではだめ
## 7/31の1ヵ月後
月を+1した場合に存在する日付の場合はOK。
“` go
t, _ := time.Parse(“2006/01/02”, “2023/07/31”)
fmt.Println(t.AddDate(0, 1, 0))
“`
“`
// 出力
2023-08-31 00:00:00 +0000 UTC
“`## 8/31の1ヵ月後
月を+1した日付(9/31)は存在しない。
これを存在する値に変換する処理が走り10/1となります。(これをGoの正規化と呼びます)
“` go
t, _ := time.Parse(“2006/01/02”, “2023/08/31”)
fmt.Println(t.AddDate(0, 1, 0))
“`
“`
// 出力
2023-10-01 00:00:00 +0000 UTC
“`# 月初の2ヵ月後の1日前を求めればよい
8/31の月初は8/1、その2ヵ月後は10/1。
その前日は9/30なので求めたかった翌月末
io/fs でのエラー解決方法 “cannot load io/fs: malformed module path “io/fs”: missing dot in first path element”
* エラー内容
* io/fsとは?
* 解決方法# 1. エラー内容
いつも通り、go言語でプログラムを書いていると、
“`
cannot load io/fs: malformed module path “io/fs”: missing dot in first path element
“`どうやらio/fsが認識していない模様…
そもそもio/fsとはなんぞや?# 2. io/fsとは?
Go1.16からio/fsパッケージとして導入されました。
主に、ファイルシステムの抽象化の役割を担い、例として、ZIPファイル等をサードパーティライブラリを使わずにGoのみで埋め込めるようになったりします。
保守のしやすさと、可読性が向上したといえるでしょう。# 3. 解決方法
今回の場合は、io/fsがGo1.16から導入されたとのことで、私が使っていたGo1.13では対応していませんでした。なので、使われる方は、バージョンをアップして使用しましょう。https://qiita.com/yuta_vamdemic/items/43fc04d98182f7bb
個人開発しました
http://4card.me/
go-gorm/genの挙動を追いかけてみた# はじめに
みなさん、こんにちは
Amebaの広告プロダクトチームでバックエンドエンジニアをやっている永井です。
この記事は、メディア事業部の広告横軸組織[PTA](https://twitter.com/PTA_CyberAgent)の[アドベントカレンダー](https://adventar.org/calendars/7539)1日目の記事となります。# 動機
仕事でDBにアクセスするアプリケーションをScalaからGoに書き換えるにあたって、テーブル定義を構造体からコツコツ作るのめんどくさいなと思い、自動でいい感じに生成してくれるツールないかなと検討した結果、genが便利そうだったので利用することにしました。
利用する分には、便利なのですが実際どのように自動生成してるのか気になったので調べてみました。# genとは
RDBのテーブル定義からGoの構造体を自動生成してくれるツールです。genで生成した構造体はgormで利用可能です。https://github.com/go-gorm/gen
# 挙動追跡
下記のコードを実行するだけでテーブル定義に沿ったGoの構造
いくつかの言語で、空白類の挙動
# これは何?
https://qiita.com/universato/items/c1f97e1843e010ed8dd8
という記事を見て、私も遊んでみた。## JavaScript
ちゃんと調べてないけど、Unicode で空白となっている文字は空白だと思う。
なので、唯一の(私調べ)目に見える空白文字、` ` (U+1680、オガム文字の空白) を半角空白の代わりに使える。
“`JavaScript:JavaScript
const a = () => {
console.log(“hello” + ”, “ + ”spaces”);
};
a( );
“`ちなみに手元の環境では「format on save」で全部半角空白にされてしまうので、この機能を OFF にする必要がある。
## go
[仕様書](https://go.dev/ref/spec#Tokens) を見ると
> Tokens form the vocabulary of the Go language. There are four classes: identifie
【個人用】Go言語チートシート
# はじめに
本記事はGo言語再履修用に作成した# 本文
## 関数
### main
“`main.go
package mainfunc main() {
println(“Hello”)
}
“`
### 自作関数
“` main.go
package mainfunc main() {
println(testfunc(1, 2))
}func testfunc(a, b int) int {
ans := a + b
return ans
}
“`
### 自作関数(戻値複数)
“`main.go
package mainfunc main() {
res1, res2 := testfunc(2, 1)
println(res1, res2)
}func testfunc(a, b int) (int,int) {
ans1 := a + b
ans2 := a – b
return ans1, ans2
}
“`
## 配列(for文)
### 既知
“`main.go
package mainfunc main
Goでマッチングサイトを作りました
# はじめに
こんにちは!
大学内マッチングサイト【まっちんぐ+R】を作成しました。
開発期間はおおよそ1週間半です。![スワイプ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982158/ba87e240-21e0-c998-4f8d-3446061ded93.gif)
# 何を作ったのか?
大学内マッチングサイトを制作しました。
[まっちんぐ+R](https://www.matchingr.tokyo)
![まっちんぐ+Rアピール.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982158/457a4a42-fecd-f743-3fb6-ec0a628d0691.jpeg)# なぜ作ったのか?
20歳になって「この人たちに出会えて本当に良かった!」と感動することが本当に多くなりました。よい経験や機会に巡り合うと、「なぜここまで来れたか」を考え、「あの人と出会ったからだ!」と奇妙な体験に面白いと感じ
Go標準パッケージtestingを利用したテスト方法
## 概要
Goには標準でtestingというパッケージが用意されている。今回はこれを使用する。
## テストコードの作成方法テストコードを書くファイルは`_test.go`という形式で命名する。
Goのテストはテスト対象のソースコードと同じパッケージに含める必要がある。
以下のような関数を作成することでテストコードを作成していく。“`go
func Test対象関数名(*testing.T) {
hogehogehogehoge
}
“`## 実際のテストコード
`decode()`という関数をテストしている。
“`go
func TestDecode(t *testing.T) {
post, err := decode(“post.json”)if err != nil {
t.Error(err)
}
if post.Id != 1 {
t.Error(“Wrong id, was expecting 1
mockery でモックを作成する方法
# はじめに
対応するときに調査に時間がかかったので備忘録として。# バージョンなど
* Golang >= 1.19 ( 多分、 <= 1.18 でも大丈夫 ) * mockery == v2.15.0 # 方法 ## セットアップ [mockery](https://github.com/vektra/mockery) を参照 ## 自分のコードのモックを作成する ### 前提条件 以下のようなファイル構成。 ```bash . └── internal └── app ├── container │ └── container.go ├── http │ ├── handler │ │ ├── health_handler.go │ │ ├── health_handler_test.go │ │ ├── send_mail_hander.go │ │ └── send_mail_ser
GoでServeHTTPにパラメーターをのっける
session管理にGCPのdatastoreを使っており、ローカルから取得するのに**300ms**ほどかかる。
本番ではもっと早くなるはずだが、middlewareで取得し、認証後またコントローラーで取得してデータを使用していた。
おそらく当初あまり気にならなかったのと、middleware自体の実装に時間がかかり、取得したデータをそのままコントローラーに流す方法がわからなかったのが理由で再取得していたようだ。今回は無駄なものを極力排除したいためその方法を調べてみた。
結果stackoverflowで発見。https://stackoverflow.com/questions/71046302/how-to-add-parameters-to-servehttp
“`go:middleware.go
func Auth(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cook
GoでTDD本の多国通貨やってみた
# この記事の内容
Go言語の学習のため、『テスト駆動開発』[^1]の第Ⅰ部 多国通貨をやってみました。
言語の違いから書籍のとおりにいかないことはあると思いますが、そういった部分も含めて「Goでどのようにできるのか」を学んでいくという趣旨です。
[^1]:https://shop.ohmsha.co.jp/shopdetail/000000004967/:::note warn
Go、Javaともにビギナーです。
:::# `testing`パッケージには`assertXXX`が無い
最初のテストで`assertEquals`の代替を探すことになったのですが、`testing`パッケージにはそのようなものはありませんでした。
https://qiita.com/Jxck_/items/8717a5982547cfa54ebc
FAQにも目を通しましたが、「エラーメッセージをきちんと書こう」とか「必要なものはすでにある」というのが理由だそうです。
なるほどと思いつつも「一つのアサーションで3行になるのは長いな」と思うこともありました。そのあたりはテストを工夫したりヘルパ
Golang 新規プロジェクトのセットアップ
# やりたいこと
滅多にやらないプロジェクトのセットアップ方法の備忘録
とりあえずHello world!を表示するサンプルプロジェクトを立ち上げる
## 環境
– macOS Monterey 12.2.1
– VSCode
– go 1.18
“`sh
$ go version
go version go1.18 darwin/arm64
“`
# プロジェクト作成
## 作業ディレクトの作成
作業用ディレクトリ作成して、移動
“`sh
mkdir sample-project
cd sample-project
“`
## パッケージ管理の初期化
Golangでは基本的に[Go Modules](https://github.com/golang/go/wiki/Modules#quick-start-example)を使用してパッケージを管理する。(Node.jsのnpmやPythonのpipのようなものです。)以前はGOPATHでパッケージ管理していたみたいですが、今はGo Modulesで管理。モジュールの初期化。
下記コマンドを実行したディレク
[golang] GormでDISTINCTを使う
# はじめに
GormでMySQLを操作していたところ、DISTINCTを使いたくなった。
[GORMのサイト](https://gorm.io/ja_JP/docs/query.html)をみてやってみたけど上手くいかなかったので、
色々自分で試す。上手くいく方法が見つかったので、そのメモ。# 結論
Select()の取得対象指定の際に、頭に”DISTINCT “を付与する# ソースコード
確認時のソースコード“` go
package mainimport (
“fmt”
“github.com/jinzhu/gorm”
_ “github.com/jinzhu/gorm/dialects/mysql”
)const (
TBL_TEST string = “Test”
)// 元のテーブル
type Test struct {
Id uint32 `gorm:”column:ID” json:ID`
Name string `gorm:”column:name” json:name`
Age
1億レコードのテーブルを扱ってみた
仕事で扱うレコード数は多くて1000万くらいだが、過去に1億レコードを扱ったという記事があり、どんなものなのか気になったため、過去に作成したポートフォリオにデータを追加してみた(ToDoアプリ)。なお調べるうちに某企業は130億レコードを扱ったみたいな記事もあり、1億レコードは決してかなり多いレコード数ではないと知った。
# 環境
* Go 1.18
* gorm
* mysql 8.0
# 1億レコード追加
tasksテーブルにレコードを追加すると、早速問題が起きた。
Gormなので“Debug()“を使ってどのようなクエリが発行されているのか確認してみた。“`sql
[0.000ms] [rows:11] SELECT * FROM `users` WHERE `users`.`id` IN (…)[1.000ms] [rows:3] SELECT * FROM `fields` WHERE `fields`.`id` IN (…)
[0.534ms] [rows:5] SELECT * FROM `milestones` WHERE `mileston