🐕
[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