2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

golangのsamber/loを使って複数の構造体スライスを一気にマッピングしたい

Posted at

概要

ある構造体の値を、別の構造体にマッピングしたいことがあると思います。

例えばインフラ層にはSELECT文を実行した結果をマッピングするための構造体Aがあって、それをドメイン層のモデルである構造体Bにマッピングして、さらにそれをクライアントに返すレスポンス用の構造体Cにマッピングして…

というように層ごとにデータ構造が変わる場合は適宜こうした操作が必要になります。
一般的にはこうした操作はヘルパー関数を作って対応されているのでしょうか。
自分はこれに対するベストプラクティスが分からないので、いい方法を知っていればぜひ教えていただきたいのですが、自分なりに samber/lo を使ってやってみたので小ネタ的な紹介です。

ユースケース

2つ以上の構造体スライスの内容を1つの構造体スライスにマッピングしたいときなどです。
例えばあるメソッドを実行すると 構造体Userのスライス構造体BlogPostのスライス が返ってくるので、それらの内容を合わせたレスポンスを生成するために 構造体UserPostResponseのスライス へマッピングするといったケースで以下のようなサンプルを作ってみました。

サンプル

main.go
package main

import (
	"fmt"

	"github.com/samber/lo"
)

type User struct {
	Name string
	Age  int
}

type BlogPost struct {
	Title   string
	Content string
}

type UserPostResponse struct {
	Name    string
	Title   string
	Content string
}

func main() {
	users, posts := getUserInfo()

	res := lo.Map(
		lo.Zip2(users, posts),
		func(model lo.Tuple2[User, BlogPost], _ int) UserPostResponse {
			user, post := model.A, model.B
			return UserPostResponse{
				Name:    user.Name,
				Title:   post.Title,
				Content: post.Content,
			}
		})

	fmt.Printf("%+v\n", res)
}

func getUserInfo() ([]User, []BlogPost) {
	users := []User{
		{Name: "のび太", Age: 9},
		{Name: "静香", Age: 9},
	}
	posts := []BlogPost{
		{Title: "ドラえもんとの出会い", Content: "お正月に机の引き出しから..."},
		{Title: "私の好きなもの", Content: "まずお風呂!食べ物は実はやき芋が..."},
	}

	return users, posts
}

下記が lo.Map のシグネチャです。

func Map[T any, R any](collection []T, iteratee func(item T, index int) R) []R

何やら難しいですが

  • 第一引数に任意の型Tのスライス
  • 第二引数に任意の型Tの要素とインデックスを引数に取り、任意の型Rを返すコールバック関数
  • コールバック関数の結果である任意の型Rのスライスが戻り値

次は lo.Zip2 のシグネチャです。

func Zip2[A, B any](a []A, b []B) []Tuple2[A, B]
  • 第一引数に任意の型Aを要素とするスライス
  • 第二引数に任意の型Bを要素とするスライス
  • 各要素がA,B型のペアを持つTuple2構造体のスライスが戻り値

あとがき

サンプルに示した UserBlogPost のスライスの長さは同じである必要があります。
普通にfor文で回してそのインデックスでBlogPostを同時にマッピングさせることもできます。

	res := make([]UserPostResponse, len(users))
	for i, user := range users {
		post := posts[i]
		res[i] = UserPostResponse{
			Name:    user.Name,
			Title:   post.Title,
			Content: post.Content,
		}
	}

sambler/lo 使って色々書いてきたけども、こっちの方がシンプルなのでいい気がしてきました🤣

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?