私が歌川です

@utgwkk が書いている

Goのstructを別のstructに変換する関数を自動生成するツールを書いた

すでに世の中にありそうな気がするけど作りました。もうあったらそっちを使いたいので教えてください。READMEがぜんぜん整備されていないので手があいたときになんとかしたい。

github.com

2023/6/19 11:53 追記

社内でcopierを教えてもらいました。

github.com

やりたいことにはおおむね合っていそうで機能も揃っていそうな印象? ただ、静的に変換できることが分かっているstructなら静的に (エラーなしで) 変換されたいかな〜という気持ちがあります。

モチベーション

以下のような2つのstructがあったとします。CreatedAt UpdatedAt はDB上でしか管理しないフィールドなので *foo.FooModel 上に対応するフィールドがないとしましょう。

package foo

type FooModel struct {
    Id   string
    Name string
    Age  int
}
package bar

type BarModel struct {
    Id        string
    Name      string
    Age       int
    CreatedAt time.Time
    UpdatedAt time.Time
}

*bar.BarModel*foo.FooModel に変換する関数あるいはメソッドを生やすことを考えると、フィールド名が一致するフィールドをマッピングして新しいstructを作って返せばよいだけなので、とくに難しいことはありません。

しかしながら、後からフィールドを足したり、そもそもフィールドの数が多くなったりすると、structのフィールドをマッピングする手間が大きくなったり、マッピングし忘れてゼロ値が引き回されていた!! という事故が起こりやすくなったりします。

go-transform-struct-genは、そういったstructの変換処理を都度手書きする手間をできるだけ減らしたい (減らせるかどうか実験したい) というモチベーションから生まれました。あとは go/ast に入門したかったとか……。

使い方

先述したようなstructが適当なパッケージにあるとして、以下のコマンドで変換関数 (メソッド) を生成できます。

% transform-struct-gen -src-struct '*github.com/utgwkk/go-transform-struct-gen/internal/fixtures/bar.BarModel' -dst-struct '*github.com/utgwkk/go-transform-struct-gen/internal/fixtures/foo.FooModel' -name ToFoo -type method
// This file is generated by github.com/utgwkk/go-transform-struct-gen
package bar

import "github.com/utgwkk/go-transform-struct-gen/internal/fixtures/foo"

func (src *BarModel) ToFoo() *foo.FooModel {
        return &foo.FooModel{
                Age:  src.Age,
                Id:   src.Id,
                Name: src.Name,
        }
}

変換元のstructのフィールドにtagを書くことで、どのフィールドにマッピングしたいかを指定することもできます。- を指定するとマッピング対象から除外することを明示できます。

package bar

type BarModel struct {
    Id        string    `transform_struct:"dst_field=Id"`
    Name      string    `transform_struct:"dst_field=Name"`
    Age       int       `transform_struct:"dst_field=Age"`
    CreatedAt time.Time `transform_struct:"-"`
    UpdatedAt time.Time `transform_struct:"-"`
}

transform_strut tagを既存のstruct定義に埋め込むツールも用意してあります (READMEで一切言及していないので書き足したい!!)。変換元のstructのフィールドと変換先のstructのフィールドのレーベンシュタイン距離を計算して、最も小さいフィールド同士を変換するようにstruct tagを埋め込むようにしています。あまりフィールド名が違いすぎるとマッピングされないので、そのときは手でstruct tagを埋めてくださいということにしています。

とりあえず手元で使ってみて、なにか進展があったらまた記事を書こうと思います。ヒマができたら……