Open3
よく使う実装

目次
- 重点的に
- slice操作
- make
- recover
- defer
- go routine
- context
- ntewrelic
- set
- lo 関数
- slice
- 複数のデータをmapで処理
- ログだし
- エラーコード echo レスポンス
- setupDBなどの innerに定義する書き方
- errgroup.Groupの書き方

lo
-
lo系共通イメージ
- スライスなどの要素が1つずつ処理の対象になるイメージ
- 関数の引数は、関数が何を返すかによって変わる
- Map
- スライスを返すのでスライスの要素になるように
- SliceToMap
- mapを返すので key, valueを返り値
- Find
- 判定処理に使うために booleanを返り値に
- Map
-
Map
- これはスライスを新しいスライスにする関数
package main
import (
"fmt"
"github.com/samber/lo"
)
type User struct {
ID int
Name string
}
func main() {
users := []User{
{ID: 101, Name: "Alice"},
{ID: 102, Name: "Bob"},
{ID: 103, Name: "Charlie"},
}
// lo.Map を使って、UserスライスからIDのスライスを抽出
userIDs := lo.Map(users, func(u User, _ int) int {
return u.ID
})
fmt.Println("Original Users:", users)
fmt.Println("Mapped User IDs:", userIDs) // Output: Mapped User IDs: [101 102 103]
}
### こんな感じでも良い
// You can edit this code!
// Click here and start typing.
package main
import (
"fmt"
"github.com/samber/lo"
)
type User struct {
ID int
Name string
}
type KeyValue struct {
Key int
Value string
}
func main() {
users := []User{
{ID: 101, Name: "Alice"},
{ID: 102, Name: "Bob"},
{ID: 103, Name: "Chaline"},
}
userIds := lo.Map(users, func(u User, index int) KeyValue {
return KeyValue{Key: index, Value: u.Name}
})
fmt.Println("Hello, 世界", userIds)
}
- Must
- エラーが発生するならpanicを起こす
- panicがおこらないなら、jstは必ずある
- エラーが発生するならpanicを起こす
package main
import (
"fmt"
"time"
"github.com/samber/lo"
)
func main() {
// 存在するタイムゾーンのロード(成功するケース)
jst := lo.Must(time.LoadLocation("Asia/Tokyo"))
fmt.Println("Successfully loaded JST:", jst.String())
// 存在しないタイムゾーンのロード(失敗するケース - この行はパニックするためコメントアウト)
// nonExistentLocation := lo.Must(time.LoadLocation("NonExistent/Location"))
// fmt.Println("Loaded NonExistent Location:", nonExistentLocation.String())
fmt.Println("Program finished successfully if no panic occurred for invalid location.")
}
- slicetoMap
- sliceは配列のようなもの
- mapにする
- 関数の返り値はkey, valueにする
- ex) (string, int)
package main
import (
"fmt"
"github.com/samber/lo"
)
type Product struct {
ID int
Name string
Price int
}
func main() {
products := []Product{
{ID: 1, Name: "Apple", Price: 100},
{ID: 2, Name: "Banana", Price: 50},
{ID: 3, Name: "Orange", Price: 120},
}
// lo.SliceToMap を使って、ProductスライスからNameをキー、IDを値とするマップを作成
productIDMap := lo.SliceToMap(products, func(p Product) (string, int) {
return p.Name, p.ID
})
fmt.Println("Original Products:", products)
fmt.Println("Product ID Map (Name -> ID):", productIDMap)
// Output: Product ID Map (Name -> ID): map[Apple:1 Banana:2 Orange:3]
}
- Find
- 1つ対象を見つけたら処理が終わる
package main
import (
"fmt"
"github.com/samber/lo"
)
func main() {
numbers := []int{10, 25, 30, 45, 50}
// lo.Find を使って、30以上の最初の偶数を見つける
if foundNum, found := lo.Find(numbers, func(n int) bool {
return n >= 30 && n%2 == 0
}) {
fmt.Printf("Found number: %d\n", foundNum) // Output: Found number: 30
} else {
fmt.Println("Number not found.")
}
// 見つからないケース
if _, found := lo.Find(numbers, func(n int) bool {
return n > 100
}) {
fmt.Println("Found number (should not happen).")
} else {
fmt.Println("Number > 100 not found (expected).")
}
}
- Ptr
package main
import (
"fmt"
"github.com/samber/lo"
)
func main() {
value := "hello"
ptrValue := lo.ToPtr(value) // string型の値 "hello" へのポインタを取得
fmt.Printf("Original value: %s\n", value)
fmt.Printf("Pointer value: %s (address: %p)\n", *ptrValue, ptrValue)
num := 42
ptrNum := lo.ToPtr(num) // int型の値 42 へのポインタを取得
fmt.Printf("Original number: %d\n", num)
fmt.Printf("Pointer number: %d (address: %p)\n", *ptrNum, ptrNum)
}

slice
-
slice
- 要素数が固定ではない、配列じゃ
-
extract
package main
import (
"fmt"
"github.com/samber/lo"
)
type Item struct {
Name string
Price int
}
func main() {
items := []Item{
{"Laptop", 1200},
{"Mouse", 25},
{"Keyboard", 75},
}
// アイテムのスライスから価格のスライスを抽出 (Extractの一般的な意味)
prices := lo.Map(items, func(item Item, _ int) int {
return item.Price
})
fmt.Println("Original Items:", items)
fmt.Println("Extracted Prices:", prices) // Output: Extracted Prices: [1200 25 75]
}
- map
package main
import (
"fmt"
"github.com/samber/lo"
)
type CompanyID int // company.ID のようなカスタム型を模擬
func main() {
companyIDs := []CompanyID{1001, 1002, 1003, 2005}
// lo.Map を使って []CompanyID を []int に変換
intCompanyIDs := lo.Map(companyIDs, func(id CompanyID, _ int) int {
return int(id)
})
fmt.Println("Original CompanyIDs:", companyIDs)
fmt.Println("Casted (mapped) to Ints:", intCompanyIDs) // Output: Casted (mapped) to Ints: [1001 1002 1003 2005]
}
- exclude
package main
import (
"fmt"
"github.com/samber/lo"
)
func main() {
// userIDs := []int{1, 2, 3, 4, 5}
// excludeUserIDs := []int{3, 5}
// slice.Exclude(userIDs, excludeUserIDs) // -> [1, 2, 4]
mainSlice := []int{10, 20, 30, 40, 50, 60}
excludeSlice := []int{20, 50, 70} // 70はmainSliceにないが、問題ない
// lo.Filter と lo.Contains を使って除外
resultFiltered := lo.Filter(mainSlice, func(item int, _ int) bool {
return !lo.Contains(excludeSlice, item)
})
fmt.Println("Original Slice:", mainSlice)
fmt.Println("Exclude Slice:", excludeSlice)
fmt.Println("Result (using lo.Filter):", resultFiltered) // Output: Result (using lo.Filter): [10 30 40 60]
// または、lo.Without (複数の引数を取るが、動的な排除リストには lo.Filter が便利)
// lo.Withoutは固定された要素を削除するのに便利
resultWithout := lo.Without(mainSlice, 20, 50)
fmt.Println("Result (using lo.Without):", resultWithout) // Output: Result (using lo.Without): [10 30 40 60]
// 複数のスライスからの除外をlo.Withoutで表現するには工夫が必要
// lo.Filter + lo.Contains が汎用性が高い
}
package main
import "fmt"
// account パッケージの Account と UserID 型をシミュレート
// 練習のため、ここではシンプルな構造体として定義します
type Account struct {
ID string // ユーザーIDをシミュレート
Username string
Email string
}
type UserID string // UserID は string のエイリアスと仮定
func main() {
// サンプルの全ユーザーデータ
allUsers := []Account{
{ID: "user001", Username: "Alice", Email: "alice@example.com"},
{ID: "user002", Username: "Bob", Email: "bob@example.com"},
{ID: "user003", Username: "Charlie", Email: "charlie@example.com"},
}
// slice.Extract の処理を標準的なGoのループで再現
// Account スライスから UserID スライスを抽出する例
var allUserIDs []UserID // UserID を格納するための新しいスライスを宣言
// allUsers スライスの各要素をループ処理
// func(_ int, s account.Account) account.UserID { return s.ID }
// に相当する処理を for ループ内で行います
for _, user := range allUsers {
// 各 Account オブジェクトから ID (string) を取り出し、
// それを UserID 型に変換して新しいスライスに追加
allUserIDs = append(allUserIDs, UserID(user.ID))
}
// 結果の表示
fmt.Println("元のユーザーデータ:")
for _, user := range allUsers {
fmt.Printf(" ID: %s, Username: %s, Email: %s\n", user.ID, user.Username, user.Email)
}
fmt.Println("\n抽出されたユーザーID:")
for _, id := range allUserIDs {
fmt.Printf(" %s\n", id)
}
// 期待される出力:
// 抽出されたユーザーID:
// user001
// user002
// user003
}