Go関連のことを調べてみた

Go関連のことを調べてみた

GoのastutilでAST処理をしてみる

前回の記事: [Goの構文解析に入門してみる #Go – Qiita](https://qiita.com/ssc-ynakamura/items/142ce6b729299d82d039)

少し前にGoの構文解析に入門してみたわけですが、前回の記事の最後では[`golang.org/x/tools/go/ast/astutil`](https://golang.org/x/tools/go/ast/astutil)(以下、`astutil`)という便利パッケージがあることに触れました。
今回はこの`astutil`パッケージを使ってみたいと思います。

標準の`ast`での処理を踏まえた上での`astutil`なので、前回の記事もご一読いただけると、より一層理解しやすくなるかと思います。
「AST(抽象構文木)って何?」という方も、前回の記事をご一読ください。

## 本記事の動作環境

本記事は次の環境で動作確認しながら書きました。

– macOS Ventura
– Go 1.22

OSについては特に環境依存はないかと思います。

Goのバージョンについては、大きく離れてい

元記事を表示

【Go1.23】range over func原理主義者のためのモジュール作りました【itermania】

# TL; DR

https://github.com/Syuparn/itermania

“`go
prime := Bind(Inc(2), func(n int) Gen[int] {
return Where(Const(n), All(Not(Eq(Mod(Const(n), Range(2, n, 1)), Const(0)))))
})

for i := range Head(prime, 10)() {
fmt.Println(i)
}
“`

“`
2
3
5
7
11
13
17
19
23
29
“`

# はじめに

Go1.23から、for文の `range` に関数を指定することができるようになります。これによって、スライスを用いない反復処理をシンプルに書くことができます。

“`go
// 0~2を繰り返すイテレータ
func rotate(yield func(int) bool) {
i := 0
for {
// yieldの引数がループ変数として渡される
if !yield(i) {
// for文本体のループ

元記事を表示

【Go言語】値レシーバ v.s. ポインタレシーバ

# はじめに

値レシーバとポインタレシーバどちらを使うべきかをこの記事では解説します。

# 値レシーバの例

[Go Playground](https://go.dev/play/p/45PS4ZLjgXd)

“`go
type customer struct {
balance float64
}

func (c customer) add(operation float64) {
c.balance += operation
}

func main() {
c := customer{balance: 100.0}
c.add(50.0)
fmt.Printf(“balance: %.2f\n”, c.balance) // balance: 100.00
}

“`

customerのbalanceフィールドの値は変更されない。

# ポインタレシーバの例

[Go Playground](https://go.dev/play/p/xt2JGopkxO_f)

“`go:ポインタレシーバ
type customer struct {
balanc

元記事を表示

[Go/DDD] BackEnd Portfolio 作成

# 前段
転職活動の一環で、簡易なバックエンドポートフォリオを作成しました。

https://github.com/tadasi/portfolio

なおコードを見せるのが目的なため、アプリケーションの中身は簡易な TODO アプリとしました。

作業時間短縮のために画面も用意していなければデプロイも想定していないので、Docker を立ち上げてローカルで curl を叩くとローカル MySQL で CRUD 処理ができるというだけの機能しか有しておりません。

なお同様の理由で単体テストの実装も割愛しております。
通常の開発ではあり得ないですが、ご容赦くださいませ。

# 概要
今回「ドメイン駆動設計(DDD)」を意識しました。

業務上でも一部 DDD の設計が取り入れられてはおりますが、本ポートフォリオにおいてはオリジナルの極めてシンプルな構成にしております。

# ディレクトリ構成
大まかには、下記のような構成です。
“`
.
├── api/
│ └── openapi
├── application/
│ ├── server/
│ │ └── mai

元記事を表示

Goでメモリアロケータを実装&ベンチマークで比較してみた

## はじめに

:::note warn
警告
以下の記事、実装はあくまで検証用です。
:::

Go 1.20 で 標準パッケージの実験的なものとして、 arena パッケージが提供されました。
[Goのメモリ管理 / Memory management in Go – Speaker Deck](https://speakerdeck.com/ymotongpoo/memory-management-in-go) のスライドを見ていて、メモリ割り当てサイズにより割り当て速度がどのように変化するのか、またメモリアロケータを実装して速度を改善することができるのかと思い今回の検証を試してみることにしました。

## TL;DR

– Goにおいて、ほとんどの通常用途ではメモリ管理の実装は不要。
– 今回の検証においては、1MB近いデータを確保する場合は、自作メモリアロケータ(TLSF)の方が約25倍ほど高速。
– ただし、unsafe.Pointerを扱わなくてはいけないため、メモリ管理のコストを払う必要がある

## 検証イメージ

アプリケーションから見た時のメモリ割り当て

元記事を表示

Go言語のAPIサーバをマルチステージビルドでAWS ECSにデプロイしたら、ヘルスチェックが通らなかった

## 要約
はじめは、ヘルスチェックに`curl`コマンドを用い、Go言語のバイナリ実行のステージに`distroless`イメージを利用する設定にしていました。

ですが、`distroless`イメージは極力コマンドなどを削った環境であり、`curl`コマンドもインストールされていないようで、ヘルスチェックが行えませんでした。

対処法の候補はいくらかあるかと思いますが、私は`distroless`イメージの使用を辞め、**`alpine`イメージを使用する**ようにし、ヘルスチェックのコマンドも`curl`ではなく`wget`を使うように変更しました。

“`Dockerfile
HEALTHCHECK CMD wget –quiet –spider http://localhost:1323/ || exit 1
“`

## 背景
### 元々のコンテナイメージ
普段Go言語のAPIサーバを構築する際、実行環境はDockerで構築しています。いままでは以下のようなDockerfileでGo言語のプログラムを実行していました。

“`Dockerfile:Docker

元記事を表示

【Go言語】部分文字列

# はじめに

スライスや配列をスライス化する際に、メモリリークが発生する可能性がありますが、文字列でも同様の事象が考えられます。(スライスについては以下を参照)

https://qiita.com/twrcd1227/items/989d8d553fc6913f01f3

# 部分文字列

“`go
func main() {
s1 := “Hello”
s2 := s1[:5]
fmt.Println(s2) // Hello
}
“`

`s2`は`s1`の部分文字列となっている。ただし、最初の5つのruneからではなく、5バイトから文字列を作成している。

ちなみに、runeについては以下で詳しく解説しています。

https://qiita.com/twrcd1227/items/45d3fb4be5bce334fae9

エンコードすると複数バイトのruneになる場合は、上記のような部分文字列は使用してはいけない。

[Go Playground](https://go.dev/play/p/8Ki9LZvuCzG)

“`go
func main() {

元記事を表示

【Go言語】stringsパッケージとbytesパッケージ

# 文字列の連結

Goには文字列を連結する方法は2通りある。

## シンプルな連結(`+=`で連結する)

スライスの全ての文字列を連結する`concat`関数を作成する。

[Go Playground](https://go.dev/play/p/veu5ot5Vd7F)

“`go
func concat(values []string) string {
s := “”
for _, value := range values {
s += value
}
return s
}
“`

これだと反復ごとに`s`は更新されず、新たな文字列がメモリから再割り当てされる。

## strings.Builderを使用する方法(事前割り当てなし)

stringsパッケージのBuilderを用いることで上記の問題が解決し、メモリ上のコピーを最小限にする。

“`go
func concat(values []string) string {
sb := strings.Builder{}
for _, value := ra

元記事を表示

Go言語でAmazonの商品検索を行う。

# やりたいこと

Go言語の勉強の一環として、Amazonの商品検索結果を取得するプログラミングを作成する。

# 環境

* Windows 11 Pro
* Go バージョン 1.22.4

# 事前準備

## アクセスキーとシークレットキーの取得

AmazonアソシエイトのAmazon Product Advertising API(PA-API)にアプリケーションを登録し、アクセスキーとシークレットキーを取得する。

https://affiliate.amazon.co.jp/

![スクリーンショット 2024-07-15 101513.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624329/e28e7417-171b-f7bc-2412-912f08d53b78.png)

## pa-apiモジュールの取得

github.com/goark/pa-apiからモジュールを取得する

“`powershell
go mod init pa-api
go get github.c

元記事を表示

【gomonkey】インライン化された関数にはモンキーパッチが効かない

# TL; DR

– コンパイラの最適化によって `gomonkey.ApplyFunc` が効かなくなることがある
– `-gcflags=all=-l` で最適化を無視することでテスト可能

https://github.com/agiledragon/gomonkey/issues/34

# はじめに
gomonkey は、関数をモンキーパッチすることができるモジュールです。ユニットテストでHTTP通信/DBアクセス関数等をモックに差し替えることで、再現しづらいコーナーケースもテストできるようになります。

https://github.com/agiledragon/gomonkey

:::note alert
モンキーパッチではunsafeを用いたメモリ書き換えを行っています。**プロダクトコード側への使用は非推奨です**。
:::

本記事では、モンキーパッチの関数 `ApplyFunc` が動作しなかった際の原因と対処法について紹介します。

# gomonkey.ApplyFunc
`ApplyFunc` を使用すると、引数に渡した関数の処理を書き換えることができ

元記事を表示

【Go言語】Trim関数

# Trim関数とは?

[strings](https://pkg.go.dev/strings)パッケージの[TrimLeft](https://pkg.go.dev/strings#TrimLeft)、[TrimPrefix](https://pkg.go.dev/strings#TrimPrefix)などのTrimXXXとなる関数のこと。

特に、TrimRight と Trimsuffixを混同してしまいがちなので、解説していきます。

# TrimRight

`TrimRight`は、末尾の文字が、第二引数に指定したルーンの集合に当てはまったら、その文字を削除します。

“`go
fmt.Println(strings.TrimRight(“123oxo”, “xo”)) // 123
“`

`123o`になりそうですが、oは`xo`の一部なので、削除されて123となります。

# TrimSuffix

TrimSuffixは、与えられた接尾辞の文字列を末尾から取り除いた値を返します。

“`go
fmt.Println(strings.TrimSuffix(“

元記事を表示

Goのfor文について

## Go言語のfor文の使い方と注意点
Go言語には、一連のステートメントを繰り返すための強力な制御構文であるfor文があります。この記事では、for文の基本的な使い方から、for-range文、無限ループ、そして注意点について詳しく解説します。
## 基本的なfor文の使い方
for文は、初期化、条件式、後続処理の3つの部分から構成されます。以下は基本的なfor文の構文です。
“`go:goファイル
for i := 0; i < 10; i++ { fmt.Println(i) } ``` ```:結果 0 1 2 3 4 5 6 7 8 9 ``` ### 条件式のみのfor文 他の言語のwhileループに似た形式で、条件式のみを使ったfor文も可能です。 ```go:goファイル i := 0 for i < 10 { fmt.Println(i) i++ } ``` この記法でも0から9までを出力します。 ### 無限ループ 無限ループは、条件式を書かずにforを使用することで実現できます。システムの監視やユーザーの入力待ちなどに使われます。 ``

元記事を表示

Go言語のジェネリクス

## Go言語のジェネリクスの使い方とその利点
Go言語は静的型付けプログラミング言語であり、型安全性を保ちながら効率的なコードを書くことができます。Go 1.18で導入されたジェネリクスは、異なるデータ型に対して再利用可能な関数やデータ構造を作成するための強力な機能です。この記事では、ジェネリクスの基本的な使い方とその利点について説明します。
## ジェネリクスとは?
ジェネリクスは、さまざまなデータ型で動作する関数やデータ構造を作成するための機能です。これにより、特定のデータ型に依存しないコードを書くことができます。例えば、整数や浮動小数点数、文字列などを扱う関数を1つのジェネリック関数として定義できます。
## 基本的な使い方
ジェネリクスを使うには、型パラメータを関数や型に追加します。型パラメータは角括弧([])内に定義され、各パラメータは大文字で始まる識別子にします。
例1: 配列の要素の合計を計算する関数
以下の例では、整数と浮動小数点数の配列の合計を計算するジェネリック関数を定義しています。
“`go:例
package main

import (
“fmt”

元記事を表示

個人メモ〜Go言語入門(少し目的のあるコードを書く編)

別記事で基礎的な文法を調べ、Hello Worldまで行った。
[個人メモ〜Go言語入門(文法と環境構築編)](https://qiita.com/PG-practice/items/42f17aa2ad43e473b033)

今回の記事ではHello Worldの次のステップとして少しコードを書いてみた。
以下を順に見ていく。
– 同一パッケージ内で複数のファイルを作成する
– 別のパッケージを作成する
– HTTPリクエスト
– AWS SDK for Go V2をインストールして、Lambda関数を呼び出す

この記事でやることを理解するために調べた内容が上記の記事にメモってあるので、この記事の内容は基本的に上記記事も見ればわかるはず。

## 前提
環境構築してhello worldまでできている。
`go mod init hello` している。
“`:go.mod
module hello

go 1.22.5
“`

## 同一パッケージ内で複数のファイルを作成する
以下の構成で、`hello.go`から`hello2.go`のメソッドを呼び出す。

構成
`

元記事を表示

Golangのスライスについて

# Golangのスライスについて
Golang(Go言語)では、スライスは非常に重要なデータ構造です。スライスは、配列の一部を参照する柔軟で強力な方法を提供します。この記事では、スライスの基本的な使い方とその特性について説明します。
## スライスの基本
スライスは、配列の一部を参照するためのデータ構造です。スライスは、配列の要素へのポインタ、長さ、および容量を持っています。以下は、スライスの基本的な宣言と使用方法です。
“`go:例
package main

import “fmt”

func main() {
// 配列を作成
arr := [5]int{1, 2, 3, 4, 5}

// スライスを作成
slice := arr[1:4]

fmt.Println(“配列:”, arr)
fmt.Println(“スライス:”, slice)
}
“`
“`:結果
配列: [1 2 3 4 5]
スライス: [2 3 4]
“`
このコードでは、arrという配列からsliceというスライスを作成しています。スライスは

元記事を表示

Goの公式ブログをただ翻訳しただけ

# セキュアなランダム性 in Go 1.22
コンピュータはランダムではありません。むしろ、ハードウェア設計者は、コンピュータが毎回同じ方法でプログラムを実行するように非常に努力しています。そのため、プログラムがランダムな数値を必要とする場合、それには追加の努力が必要です。伝統的に、コンピュータ科学者やプログラミング言語は、統計的ランダム性と暗号的ランダム性という2つの異なる種類のランダム数を区別してきました。Goでは、それらはそれぞれ `math/rand` と `crypto/rand` によって提供されています。この投稿では、Go 1.22がこれら2つをどのように近づけたかについて説明します。具体的には、`math/rand(および前回の投稿で言及した math/rand/v2)`で暗号的ランダム数のソースを使用することにより、より良いランダム性を実現し、開発者が誤って `math/rand` を使用した場合の被害を大幅に減らすことができました。
Go 1.22が何をしたのかを説明する前に、統計的ランダム性と暗号的ランダム性の違いを詳しく見てみましょう。
## 統計的ランダム性

元記事を表示

個人メモ〜Go言語入門(文法と環境構築編)

機会があってGoに入門してみた。Goはシンプルで機能が少ないらしいので、基本的なことを抑えればある程度読めそうと期待。
この記事で書くのは以下の二つ。

– Hello World
環境構築まではやる。それ以外に多少目的あるコード書くのもやった。それは別記事に分ける。[個人メモ〜Go言語入門(少し目的のあるコードを書く編)](https://qiita.com/PG-practice/items/7dbfc617f7d627a8c736)
– 文法についてメモ
自分が概念を思い出せるように書くだけ。for文とかは調べればすぐ出てくるので、へぇと思ったところだけ。ゴルーチンのところはサンプルを動かしつつ。

# 環境構築
OS: Ubuntu 24.04 LTS

コマンドやバージョンは公式から。
https://go.dev/dl/
https://go.dev/doc/install

以下を実行
“`bash
curl -OL https://go.dev/dl/go1.22.5.linux-amd64.tar.gz
rm -rf /usr/local/go && sudo ta

元記事を表示

【Go】名前付き戻り値を使うべきなのか

# ブランクreturnの挙動
名前付き戻り値は以下のようにブランクreturnを使用することができる。
“`go:
package main

import “fmt”

func add(num1, num2 int) (addResult int) {
addResult = num1 + num2;
return
}

func main() {
fmt.Println(add(1, 2)) //3
}
“`

ではブランクreturnに誤って引き算の計算結果を記述した際の動作はどうなるのだろうか。
“`go:
package main

import “fmt”

func add(num1, num2 int) (addResult int) {
addResult = num1 + num2;
return num1 – num2
}

func main() {
fmt.Println(add(1, 2)) // -1
}
“`
addメソッドは-1を返してしまうようだ。名前付き戻り値はreturnに値を記述した時はその値を返してしまうようだ。

元記事を表示

Goのエラーハンドリングざっくり

## GO言語のエラーハンドリング
GO言語では、エラーを示すために組み込みの`error`型を使用します。例えば、os.Open関数はファイルを開く際に失敗すると非nilの`error`値を返します。
“`go:例
f, err := os.Open(“filename.ext”)
if err != nil {
log.Fatal(err)
}
// ファイルを開いた後の処理
“`
#### `error`型の詳細
`error`型はインターフェース型であり、以下のように定義されています。
“`go:例
type error interface {
Error() string
}
“`
最も一般的な`error`の実装は、`errors`パッケージの`errorString`型です。

“`go:例
type errorString struct {
s string
}

func (e *errorString) Error() string {
return e.s
}
“`
`errors.New`関数を使用して`errorSt

元記事を表示

Goのregexpとregexp2のパッケージの違い

## regexp パッケージ
regexpはGoの標準ライブラリに含まれている正規表現パッケージです。以下はその主な特徴です:
特徴
#### 1. シンプルで高速:
– regexpはシンプルで高速な正規表現エンジンを提供します。
– 基本的な正規表現機能をサポートしています。
#### 2. RE2エンジン:
– regexpはGoogleのRE2エンジンをベースにしており、バックトラッキングをサポートしないため、常に線形時間で動作します。
– 無限ループやスタックオーバーフローのリスクがありません。
#### 3.基本的な機能:
– 名前付きキャプチャグループや条件付きパターンなどの高度な機能はサポートしていません。
##### 使用例
“`go:例
package main

import (
“fmt”
“regexp”
)

func main() {
pattern := `[a-zA-Z]+`
re := regexp.MustCompile(pattern)
text := “Hello123 World

元記事を表示

OTHERカテゴリの最新記事