サンプルコード
Go のサンプルコード一覧
Go で「○○するには」を解決するコードサンプル。73 件。
他の言語から探す
2つの日付の差を求めるには
`Sub` は `time.Duration` を返す。`Duration` には `Hours()`・`Minutes()`・`Seconds()` はあるが日数を返すメソッドは無いため、日数が欲しければ `Hours()` を 24 で割る。日付だけを比べたい場合も `time.Time` を使うので、時刻部分をゼロで揃えてから引く必要がある。
配列を条件で絞り込むには
Go には条件で絞り込んだ新しいスライスを返す標準関数が無いので、`append` で積み直すのが基本形になる。`make` の第 3 引数に元の長さを渡しておくと、途中でのメモリ再確保を避けられる。
環境変数を削除するには
`os.Unsetenv` で変数を削除する。`os.Setenv("KEY", "")` は値を空にするだけで変数は残るため、`os.LookupEnv` の戻り値 `ok` は `true` のままである。存在の有無を判定したいときは `os.Getenv` ではなく `os.LookupEnv` を使う。
QRコードを生成するには
`qrcode.New` にデータと誤り訂正レベル(`qrcode.Medium`)を渡し、`WriteFile` で一辺 256 ピクセルの PNG を書く。余白は既定で付き、選ばれた版は `VersionNumber` で読める。
ディレクトリ内のファイル一覧を取得するには
`os.ReadDir` は `DirEntry` のスライスをファイル名順に並べて返すため、追加のソートは要らない。`DirEntry` は `IsDir()` を持っており、判定のために別途 `Stat` を呼ぶ必要がない。
ネストしたJSONから値を取り出すには
構造体へ流し込む前に既定値を入れておく。`json.Unmarshal` は JSON に存在するフィールドだけを書き換え、欠けているフィールドには触れないため、これで既定値が残る。入れ子は構造体を入れ子にするか、ポインタにして `nil` で欠落を判定する。
乱数のシードを固定して同じ結果を再現するには
`math/rand/v2` では `rand.New(rand.NewPCG(seed1, seed2))` でシード付きの生成器を作る。トップレベルの `rand.IntN` などはシードを指定できないため、再現したい処理では生成器を自分で持って関数に渡す。
HTTPリクエストにヘッダーを付けるには
http.Get にはヘッダーを渡す口が無いため、http.NewRequest でリクエストを組み立ててから req.Header.Set で足す。Set は同名ヘッダーを置き換え、Add は同名のまま追加するので、1 つだけ持たせたいヘッダーには Set を使う。
配列からランダムに1つ選ぶには
`math/rand/v2` の `rand.IntN(n)` は 0 以上 n 未満の整数を返すので、`len` を渡してスライスの添字に使う。n が 0 以下だと panic するため、空のスライスかもしれないときは先に `len` を確かめる。
ランダムな文字列を生成するには
`crypto/rand` の `rand.Int` に文字集合の長さを渡すと、0 以上その長さ未満の整数を偏りなく得られるので、1 文字ずつ選んで並べる。Go 1.24 以降は `rand.Text()` が 26 文字の Base32 文字列を返すので、文字集合を問わないトークンならこれで足りる。`math/rand` は暗号用途に向かない。
環境変数を設定するには
os.Setenv はこのプロセスの環境を書き換え、error を返すので本来は確認したほうがよい。exec.Cmd の Env を nil のままにすると親の環境がそのまま引き継がれるため、一部だけ変えたいときは os.Environ() に追記する。同じキーが重複した場合は後ろの値が優先される。親の環境に `LOG_LEVEL=info` がある状態で `LOG_LEVEL=debug` を追記して実行すると、子プロセスには `debug` が渡った。
UUIDを生成するには
標準ライブラリに UUID は無く、`github.com/google/uuid` を `go get` で取り込む。`go get` を忘れると `no required module provides package` で止まる。`uuid.New()` はバージョン 4、`uuid.NewV7()` は時刻順に並ぶバージョン 7 を返す。`Version()` の戻り値をそのまま出すと `VERSION_4` と表示されるので、数字にするなら `int` に変換する。
範囲を指定して乱数を得るには
Go 1.22 以降の `math/rand/v2` は、種を設定しなくても実行のたびに違う値が出る。`IntN(n)` は 0 以上 `n` 未満の整数を返すので、範囲の幅を渡して下限を足す。暗号用途には `crypto/rand` の `rand.Int` を使い、上限は `math/big` の整数で渡す。
配列をランダムに並べ替えるには
`math/rand/v2` の `rand.Shuffle` は、要素数と「2 つの添字を入れ替える関数」を渡す形で、スライスを直接並べ替える。新しいスライスで 0 から n-1 の並べ替えがほしいときは `rand.Perm(n)` を使い、その結果を添字として使う。
.env ファイルを読み込むには
`godotenv.Load` は .env を読み、値を環境変数に設定する。ファイルが無いと `open .env: no such file or directory` という `error` を返すので、.env を任意扱いにするなら `err` をログに落とすだけにして処理を続ける。godotenv は既存の環境変数を上書きしない点も python-dotenv と同じで、`PORT=1111` を付けて起動すると .env に `PORT=8080` があっても 1111 が出力された。
文字列のSHA-256ハッシュ値を求めるには
標準ライブラリの `crypto/sha256` の `Sum256` は、32 バイトの配列(`[32]byte`)を返す。16 進数の文字列にするには `hex.EncodeToString(sum[:])` か `%x` の書式を使う。複数回に分けて渡すときは `sha256.New()` で作ったハッシュに `Write` を重ね、最後に `Sum(nil)` で取り出す。
文字列が含まれるか調べるには
`strings.Contains` が部分文字列の判定で、既定では大文字小文字を区別する。名前の似た `ContainsAny` は「第2引数の文字のいずれかが含まれるか」を見る別物なので、部分文字列の判定に使うと意図せず `true` になる。大文字小文字を無視した一致だけが要るなら `strings.EqualFold` を使う。
日付をJSON文字列にするには
`time.Time` は `MarshalJSON` を実装していて、RFC 3339 の文字列になる。`Unmarshal` で `time.Time` にも戻るため、変換コードは要らない。未設定のときに出力したくないフィールドは、構造体のままだと `omitempty` が効かない。Go 1.24 以降は `omitzero` を付ければ `time.Time` のままゼロ値を省略でき、それより前の版では `*time.Time` にして `nil` を入れる。
日付文字列を日付型にするには
`time.Parse` のレイアウトは `%Y` のような書式記号ではなく、参照時刻 `2006-01-02 15:04:05` を並べ替えて表す点が独特である。文字列にオフセットが無く、かつ `time.Parse` を使うと結果は UTC になるため、地域時刻として読みたいときは `time.ParseInLocation` に場所を渡す。書式不一致は `error` で返るので戻り値を必ず確認する。
配列から重複を除くには
Go には出現順を保つ重複排除の標準関数が無いため、出現済みを `map` に記録しながら新しいスライスへ積み直す。`slices.Compact` は隣り合った重複しか潰さないので、単独で使う前に並べ替えが要る。
正規表現の特殊文字をエスケープするには
`regexp.QuoteMeta` は正規表現で特別な意味を持つ文字の前に `\` を付ける。不正なパターンを `regexp.Compile` に渡すとエラーが返り、`regexp.MustCompile` に渡すと panic するので、外から来た文字列は `QuoteMeta` に通してから渡す。`ReplaceAllString` は置換文字列の `$1` を展開し、存在しないグループは空にするため、そのまま入れたいときは `ReplaceAllLiteralString` を使う。
文字列の前後の空白を除去するには
`strings.TrimSpace` は Unicode の空白定義に従って前後の空白を落とすので、全角スペース(U+3000)も除去される。`strings.Trim` / `TrimLeft` / `TrimRight` に渡す第 2 引数は cutset と呼ばれる「除去する文字の集合」で、文字列そのものとしては扱われない。接頭辞・接尾辞を外したいときは `TrimPrefix` / `TrimSuffix` を使う。
ホームディレクトリのパスを取得するには
`os.UserHomeDir` は Unix で環境変数 `HOME` だけを読み、未設定または空のときはエラーを返す。passwd を引く `user.Current()` の `HomeDir` は `HOME` を見ないので、`HOME` を書き換えても `/home/taro` のままになる。ファイル API の `os.Stat("~")` は展開せず、`~` という名前を探して存在しないエラーを返す。
HTTP POSTでJSONを送るには
`json.Marshal` した結果を `bytes.NewReader` で `io.Reader` に包んで渡す。`client.Post` の第 2 引数が `Content-Type` なので、ヘッダを別に組み立てる必要はない。既定の `http.DefaultClient` にはタイムアウトが無いため、応答しない相手で詰まらないよう `http.Client` を自分で組み立てている。受け取る構造体のフィールドは `ID` で JSON のキーは `id` だが、`encoding/json` は大文字小文字を区別せずに照合するので、タグが無くても値が入る。実行すると `201 101` と表示される。
ファイルを読み込むには
os.ReadFile はファイル全体を一括で読み込み []byte を返すので、文字列として扱うときは string() で変換する。string() はバイト列を検査せずにそのまま変換するため、Shift_JIS のファイルを読んでもエラーにならず、文字化けした文字列が返る。UTF-8 として正しいかは utf8.ValidString で確かめ、巨大なファイルでは bufio.Scanner による逐次読み込みを検討する。
整数を2進数や16進数の文字列にするには
`strconv.FormatInt` と `fmt` の書式指定 `%b` `%o` `%x` で文字列にし、`strconv.ParseInt(text, base, bitSize)` で戻す。`ParseInt` は `0x` 付きの文字列を基数 16 では読めずエラーにするので、接頭辞ごと読むなら基数に 0 を渡す。桁数が `bitSize` に収まらないときもエラーになる。
JSONをパースするには
json.Unmarshal には構造体のポインタを渡す。値のまま渡すと「json: Unmarshal(non-pointer main.User)」のエラーになる。小文字始まりの非公開フィールドは json タグを付けても無視されるため、フィールドは大文字で始め、json タグで JSON 側のキー名と対応付ける。
オブジェクトをJSON文字列にするには
`json.Marshal` は 1 行、`json.MarshalIndent` は整形した `[]byte` を返す。エクスポートされていない小文字始まりのフィールドは出力されないため、JSON 側のキー名は json タグで指定する。既定では `<` `>` `&` が HTML 用にエスケープされ、`<b>&</b>` は \u003cb\u003e\u0026\u003c/b\u003e のように出力される。そのまま出したいときは `json.Encoder` の `SetEscapeHTML(false)` を使う。
JSONをファイルに保存するには
json.NewEncoder をファイルに向けて書き、Close のエラーまで確かめてから os.Rename で置き換える。Go の JSON 出力は既定で & < > を \u0026 などにエスケープするので、URL を含む設定ファイルを人が読むなら SetEscapeHTML(false) を指定する。Encode は値の末尾に改行を付けるが、json.MarshalIndent の結果には付かない。
バイト列を16進数の文字列にするには
標準ライブラリの `encoding/hex` の `EncodeToString` と `DecodeString` で往復できる。`DecodeString` は不正な文字や奇数桁を `error` として返すので、戻り値の `err` を必ず確かめる。
配列を文字列に連結するには
strings.Join は []string しか受け取らないため、数値のスライスは strconv.Itoa などで先に []string へ変換する必要がある。容量を len で確保しておくと連結時の再確保を避けられる。
文字列を分割するには
`strings.Split` は区切り文字列で分けたスライスを返し、要素数を絞りたいときは `strings.SplitN` に上限を渡す。区切りは正規表現ではなくただの文字列として扱われるため、記号をそのまま渡してよい。空白区切りは `strings.Fields` のほうが連続空白をまとめてくれる。
文字列をUTF-8のバイト列にするには
Go の文字列は元から UTF-8 のバイト列なので、`[]byte(text)` は変換というよりバイト列としての見方を変えるだけである。`len` が返すのはバイト数で、文字数は `utf8.RuneCountInString` で数える。壊れたバイト列を `string` にしても例外にはならないため、`utf8.Valid` で自分で確かめる。
文字列をBase64にするには
encoding/base64 の StdEncoding が標準の変換で、URL セーフ版は URLEncoding、さらにパディングを付けない版は RawURLEncoding である。デコードの DecodeString はエラーを返すので、外部から受け取った文字列を戻す場面では err を必ず確認する。
ファイルの文字コードを変換するには
標準ライブラリは Shift_JIS を扱えないため、golang.org/x/text を go get し、japanese.ShiftJIS.NewDecoder を transform.Bytes に渡して変換する。不正なバイトがあっても err は nil のまま U+FFFD に置き換わるので、壊れたファイルを見つけたいときは変換後の文字列に U+FFFD が混ざっていないかを確かめる。
HTMLの特殊文字をエスケープするには
標準の html パッケージの EscapeString が変換、UnescapeString が元に戻す関数である。二重引用符は " ではなく " に、単一引用符は ' に変換される。html/template のテンプレートは出力する場所に応じて自動でエスケープするため、この関数は手で組み立てた HTML に値を埋め込む場面で使う。
HTTP GETリクエストを送るには
http.Get ではなく http.Client を組み立てているのは、既定のクライアントにタイムアウトが無く応答しない相手を無期限に待ってしまうためである。res.Body.Close() を defer するのは、閉じ忘れると接続が再利用されずリークするからである。
文字列をURLエンコードするには
クエリ用の QueryEscape はスペースを + にし、パス用の PathEscape は %20 にする。PathEscape は & や = を変換しないため、クエリの値には使わない。複数のパラメータは url.Values にまとめて Encode するとキー順に並ぶ。
日付を書式付きの文字列にするには
Go の書式は %Y のような指定子ではなく「2006-01-02 15:04:05」という参照時刻そのものを並べて表す。数字の組み合わせに意味があるため、覚えていないうちは time.RFC3339 などの定数を使うほうが安全である。time.Local は実行環境のタイムゾーンに従うので、RFC3339 の末尾は日本時間の環境で +09:00、UTC の環境で Z になる。
文字列の長さを取得するには
len(s) は文字数ではなくバイト数を返すため、日本語は 1 文字 3 バイトで数えられる。文字数が必要なときは utf8.RuneCountInString を使う。[]rune に変換しても数えられるが、変換のためにメモリを確保する分だけ無駄が出る。
ファイルが存在するか調べるには
os.Stat のエラーには権限不足なども含まれるため、err != nil をそのまま「存在しない」と読み替えてはいけない。存在しないことだけを判定するときは errors.Is(err, fs.ErrNotExist) を使う。
UNIXタイムスタンプを日付に変換するには
time.Unix は秒とナノ秒を受け取り、ローカルタイムゾーンの time.Time を返す。UTC で扱うなら UTC() を付け、地域の時刻にするなら LoadLocation で得た Location を In に渡す。ミリ秒は UnixMilli で渡す。
配列に要素が含まれるか調べるには
Go 1.21 以降は標準の slices パッケージに Contains と Index があり、手書きのループが要らなくなった。比較は == で行われるため要素は比較可能な型である必要があり、条件で探すときは ContainsFunc を使う。
現在時刻を取得するには
time.Now() はローカルタイムゾーンを保持した time.Time を返す。Go の書式指定は %Y ではなく「2006-01-02 15:04:05」という参照時刻を並べる独自方式なので、自前で組み立てるより time.RFC3339 などの定数を使うほうが間違えにくい。
ディレクトリを作成するには
os.Mkdir は親が無くても既にあっても失敗するので、準備処理には親までまとめて作る os.MkdirAll を使う。MkdirAll は既にディレクトリがあれば nil を返すため何度呼んでも安全で、失敗の種類は errors.Is と fs.ErrNotExist などで見分ける。
環境変数を読むには
os.Getenv は未設定でも空文字を返すだけでエラーにならず、空文字で設定された場合と区別できない。区別したいときは os.LookupEnv を使い、第 2 戻り値の ok で存在を判定する(空文字で設定したときも ok は true になる)。
配列をソートするには
sort.Ints や sort.Strings は基本型のスライスをその場で昇順に並べ替える。独自の基準や降順にするときは sort.Slice に比較関数を渡す。いずれも元のスライスを破壊的に変更する。
数値をゼロ埋めするには
fmt の書式指定 %05d は、幅 5 に足りない分を符号の後ろのゼロで埋める。幅を実行時に決めるときは %0*d と書き、幅を引数で渡す。strings.Repeat で自前に足す書き方は符号を区別しないので、負の数では 00-42 のように崩れる。
数値を指定した範囲に収めるには
Go 1.21 で入った組み込みの min と max を組み合わせ、cmp.Ordered の型パラメータで整数・浮動小数点数・文字列のどれにも使えるようにする。go.mod の go ディレクティブが 1.20 以下だと built-in max requires go1.21 or later でコンパイルが止まるので、go 1.21 以上にしておく。
文字列を置換するには
strings.ReplaceAll は全置換で、回数を制限するときは strings.Replace の第 4 引数に回数を渡す。回数に -1 を渡すと ReplaceAll と同じ動作になり、どちらも正規表現ではないので . のような記号も文字どおりに置き換わる。
数値を3桁区切りにするには
fmt の書式指定には 3 桁区切りが無いため、strconv.FormatInt で文字列にしてから後ろから 3 桁ごとにカンマを差し込む。符号を付けたまま区切ると -123456 が -,123,456 になるので、負の数は符号を外してから区切る。ロケールに合わせて区切りたいときは golang.org/x/text/message の Printer を使うと、language.Japanese なら 1,234,567、language.German なら 1.234.567 と書式化できる。
整数の割り算で商と余りを求めるには
整数どうしの / は商を 0 の側へ切り捨て、% の余りは割られる数と同じ符号になる。0 以上の余りが欲しいときは、負になった余りに割る数を足して補正する。変数の 0 で割ると実行時に panic: runtime error: integer divide by zero で止まり、a / 0 のように定数の 0 で割る式はコンパイル時に invalid operation: division by zero になる。
小数を指定桁で丸めるには
math.Round は 0 から遠い側へ、math.RoundToEven は偶数の側へ整数に丸める関数で、桁数を指定する引数は無いので 100 倍して丸めてから割り戻す。1.005 を 100 倍すると 100.49999999999999 になるため、この方法では 1 に丸まる。表示用の文字列が欲しいだけなら fmt.Printf の %.2f を使えばよいが、こちらも内部の値どおりに丸めるので 1.005 は 1.00 になる。
環境変数を真偽値として読むには
strconv.ParseBool が受け付けるのは 1・t・T・TRUE・true・True と 0・f・F・FALSE・false・False だけで、yes や on、tRuE のような大文字小文字の混在はエラーになる。前後の空白も許さないので、strings.TrimSpace で取り除いてから渡す。
パスからファイル名を取り出すには
filepath.Base は最後の要素を返し、末尾の / は取り除いてから判定する。空文字のパスには . を、ルートには / を返すので、空文字が返ることを前提にした判定は書かない。拡張子を除いた名前を返す関数は無いため、filepath.Ext で求めた拡張子を strings.TrimSuffix で取り除く。URL のパスのように常に / で区切られる文字列には、OS の区切り文字に従う filepath ではなく path.Base を使う。
ファイルに書き込むには
os.WriteFile はファイルの作成・書き込み・クローズをまとめて行う。第3引数はファイル作成時のパーミッションで、既存ファイルを上書きする場合は使われない。追記するときは os.OpenFile に O_APPEND と O_WRONLY を渡し、ファイルが無いときに作らせるなら O_CREATE も加える。
HTTPでファイルをダウンロードするには
http.Client の Get はリダイレクトを自動で追う一方、404 や 500 でも err を返さないので、StatusCode を確かめてから io.Copy でファイルへ写す。Client の Timeout は本文を読み終えるまでを含む上限なので、ダウンロードで短くしすぎると大きなファイルが途中で切れる。Close もエラーを返しうるため、戻り値を確かめてから os.Rename で置き換える。
正規表現で大文字小文字を区別せずに一致させるには
Go の regexp にはフラグを渡す引数が無いため、パターンの先頭に (?i) と書いて指定する。(?i:...) の形にすればグループの内側だけに効かせられるので、一部だけ大文字小文字を無視したいときはそちらを使う。
未実行
配列の最大値と最小値を求めるには
slices パッケージの slices.Max と slices.Min がスライスの最大値と最小値を返す(Go 1.21 以降)。空のスライスを渡すと panic になるため、長さを確かめてから呼ぶ。値を引数に並べて比べるだけなら、同じく Go 1.21 で入った組み込み関数の max と min が使える。
親ディレクトリのパスを取得するには
filepath.Dir は最後の区切り文字より後ろを取り除き、残りを Clean して返す。data/logs/ のように末尾に / が付いたパスでは最後の要素が空とみなされてそのディレクトリ自身が返るので、ディレクトリのパスを受け取る場面では先に filepath.Clean で末尾の区切り文字を落とす。
相対パスを絶対パスにするには
filepath.Abs はカレントディレクトリを前に付けてから Clean するので、.. も取り除かれる。ファイルが存在するかは確かめず、シンボリックリンクも解決しないため、実体のパスが必要なら続けて filepath.EvalSymlinks を呼ぶ。
ファイルの拡張子を取り出すには
filepath.Ext は最後のドット以降をドット付きで返す。拡張子を除いた名前を返す関数は無いので、Base で取り出したファイル名から strings.TrimSuffix で取り除く。.bashrc のようにドットで始まる名前は、Python や Node.js と違って名前全体が拡張子になる。
パスを連結するには
ファイルシステムのパスには、OS の区切り文字を使う filepath.Join を選ぶ。path パッケージは常に / で区切るので URL などに向き、Windows のファイルパスに使うと区切り文字が混ざる。filepath.Join は途中の絶対パスも普通の要素としてつなぎ、結果を Clean してから返す。
日付に日数を足すには
time.Time の AddDate(年, 月, 日) に日数を渡すと新しい time.Time が返る。月末を超える日付は正規化されるため、1 月 31 日に 1 か月を足すと 2 月 31 日ではなく 3 月 3 日になる。月の加算で月末に揃えたい場合は自分で調整する必要がある。
ファイルをコピーするには
標準ライブラリにファイルコピー専用の関数は無いので、開いた 2 つのファイルを io.Copy でつなぐ。上書きの可否は開くときのフラグで決まり、os.Create は切り詰めて開く動作なので、既存を守りたいときは O_EXCL を付けた os.OpenFile を選ぶ。
文字列を数値に変換するには
strconv.Atoi が 10 進整数用の短縮形で、基数やビット幅を変えたいときは ParseInt や ParseFloat を使う。戻り値の第 2 要素が error なので、変換の失敗はその場で受け取って処理する。error を無視すると失敗時に 0 が入ったまま処理が進むため、入力由来の値では必ず確認する。
2つのJSONをマージするには
map[string]any へ Unmarshal すると入れ子も map[string]any になるので、型アサーションで両方がマップのときだけ再帰する。マップの代入は参照を渡すため、元の値を壊さないよう新しいマップへ複製してから書き換える。
未実行
環境変数の一覧を取得するには
os.Environ は名前と値を = で連結した文字列のスライスを返すため、値に = を含む変数(PATH の一部など)を壊さないよう strings.Cut で最初の = だけを区切りにする。名前だけの一覧が欲しいときも同じ分割で取り出す。
未実行
正規表現に一致する部分をすべて取り出すには
FindAll 系はどれも第 2 引数に上限件数を取り、-1 が「全件」を意味する。グループまで欲しいときは FindAllStringSubmatch、一致全体だけで足りるときは FindAllString と、必要な形に合わせて選ぶ。
未実行
HTTPリクエストにタイムアウトを設定するには
http.Client の Timeout は接続からボディを読み終えるまでの全体に効き、ゼロ値のままだと上限なしになる。リクエストごとに変えたい場合は context.WithTimeout を使い、両方指定したときは先に切れたほうが勝つ。
未実行
正規表現で部分文字列を取り出すには
FindStringSubmatch は一致全体を先頭に、以降へグループを並べたスライスを返す。一致しなければ nil が返るので、添字でアクセスする前に確認する。名前付きグループは SubexpIndex で添字に変換すると、パターンを直したときの取り違えを防げる。
未実行
文字列が正規表現に一致するか調べるには
regexp.MustCompile はコンパイルに失敗するとパニックするので、リテラルで書いたパターンに使う。実行時に組み立てたパターンなら regexp.Compile を使い、error を受け取って処理する。バッククォート文字列にすると、バックスラッシュを二重に書かずに済む。
未実行
正規表現で置換するには
ReplaceAllString は一致した箇所をすべて置き換える。置換文字列の中では $1 で後方参照できるが、$1x と続けて書くと「1x という名前のグループ」として読まれてしまうため、直後に文字が続くときは ${1} と中括弧で囲む。
未実行