🐕
[Golang] 構造体の型を変換する方法
結論
"github.com/jinzhu/copier" が便利です。
このパッケージは、以下のことができます。
- フィールドから同名のフィールドにコピーする
- メソッドから同じ名前のフィールドにコピーする
- フィールドから同じ名前のメソッドへコピー
- スライスからスライスへのコピー
- 構造体からスライスへコピー
- マップからマップへのコピー
- タグを持つフィールドのコピーを強制する
- タグの付いたフィールドを無視する
- ディープコピー
これを使うことで簡単に型変換が可能になります。
どう使うか
今回の場合は、 Person 型から、必要なフィールド値のみを CastPerson 型にコピーする方法を紹介します。
Person と CastPerson で同じフィールドは Name Age From なので、これをコピーしていきます。
package main
import (
"fmt"
"github.com/jinzhu/copier"
)
type Person struct {
Name string
Age int
Hobby string
From string
}
type CastPerson struct {
Name string
Age int
From string
HairColor string
}
func main() {
p := Person{Name: "Yamamoto", Age: 25, Hobby: "plants", From: "Japan"}
castPerson := CastPerson{HairColor: "red"}
fmt.Println(castPerson)
if err := copier.Copy(&castPerson, &p); err != nil {
panic(err)
}
fmt.Println(castPerson)
}
main.go ファイルを実行します。
$ go run main.go
結果は以下の通り、Person型から必要なフィールドのみコピーすることができました🎉
{ 0 red} // コピー前
{Yamamoto 25 Japan red} // コピー後
もし CastPerson型 のフィールドに Person型 に存在しないフィールドがあった場合、
そのフィールドが上書きされる心配もないです。
上のコード例でいくと、 HairColor は上書きされていません。
いつ使ったのか?
構造体の型をレスポンスに必要な型に変換する必要がありました。
初めは以下のようにfor文を使って data型 の値をそれぞれ Person型 のインスタンスに値を入れていくということをしていました。
package main
type Friend struct {
Name string
Age int
}
type Person struct {
From string
Friends []Friend
}
func main() {
persons := make([]Person, 0)
friends := make([]Friend, 0)
// dataはDBなどから取得した値と仮定
for i, v := range data.Friends {
if len(v.Friends) > 0 {
friends = append(friends, Friend{
Name: v.Friends[i].Name,
Age: v.Friends[i].Age,
})
}
persons = append(persons, Person{
From: v.From,
Friends: friends,
})
}
}
👆 これが
👇 こうなる。
package main
import (
"github.com/jinzhu/copier"
)
type Friend struct {
Name string
Age int
}
type Person struct {
From string
Friends []Friend
}
func main() {
persons := make([]Person, 0)
if err := copier.Copy(&persons, &data); err != nil {
panic(err)
}
}
Discussion