Skip to content

copier

リポジトリ:jinzhu/copier: Copier for golang, copy value from struct to struct and more (github.com)

ドキュメント:jinzhu/copier: Copier for golang, copy value from struct to struct and more (github.com)

copier は Go での型コピーのためのライブラリで、主に構造体から構造体への変換に使用されます。gorm と同じ作者で、以下の特徴があります:

  • ディープコピー
  • 同じ名前のフィールドをコピー
  • スライスをコピー
  • マップをコピー
  • メソッドをコピー

copier のコピーはリフレクションに依存しているため、いくつかのパフォーマンス損失があります。一般的に、この種の型変換ライブラリは 2 つのカテゴリに分かれます:1 つは copier のようなリフレクションベース、もう 1 つはコード生成ベースで、型変換コードを生成します。この方法はパフォーマンス損失を引き起こさず、同様のライブラリは jmattheis/goverter です。

インストール

sh
go get github.com/jinzhu/copier

使用方法

このライブラリの使い方は非常にシンプルですが、非常に実用的です。2 つの関数のみを公開しています。1 つは copier.Copy です。

go
func Copy(toValue interface{}, fromValue interface{}) (err error)

もう 1 つは copier.CopyWithOption で、コピー動作のカスタム設定を許可します。デフォルトでは、ディープコピーは実行されません。

go
type Option struct {
  IgnoreEmpty   bool
  CaseSensitive bool
  DeepCopy      bool
  FieldNameMapping []FieldNameMapping
}

func CopyWithOption(toValue interface{}, fromValue interface{}, opt Option) (err error)

以下は、異なる構造体タイプ間での変換の例です。UserStudent 構造体は関連性のない完全に異なるタイプです。

go
type User struct {
  Id   string
  Name string
  // 宛先構造体として使用する場合、このフィールドを無視
  Address string `copier:"-"`
}

type Student struct {
  // フィールド名を指定
  StudentId   string `copier:"Id"`
  StudentName string `copier:"Name"`
  Address     string
  School      string
  Class       string
}

func main() {
  student := Student{
    StudentId:   "123",
    StudentName: "jack",
    Address:     "usa",
    School:      "MIT",
    Class:       "AI",
  }
  user := User{}
  if err := copier.Copy(&user, &student); err != nil {
    panic(err)
  }
  fmt.Printf("%+v\n", student)
  fmt.Printf("%+v\n", user)
}

出力

{StudentId:123 StudentName:jack Address:usa School:MIT Class:AI}
{Id:123 Name:jack Address:}

スライスのコピー

go
func main() {
  student := []Student{
    {
      StudentId:   "123",
      StudentName: "jack",
      Address:     "usa",
      School:      "MIT",
      Class:       "AI",
    },
    {
      StudentId:   "123",
      StudentName: "jack",
      Address:     "usa",
      School:      "MIT",
      Class:       "AI",
    },
  }

  var user []User
  if err := copier.Copy(&user, &student); err != nil {
    panic(err)
  }
  fmt.Printf("%+v\n", student)
  fmt.Printf("%+v\n", user)
}

出力

[{StudentId:123 StudentName:jack Address:usa School:MIT Class:AI} {StudentId:123 StudentName:jack Address:usa School:MIT Class:AI}]
[{Id:123 Name:jack Address:} {Id:123 Name:jack Address:}]

マップのコピー

go
type User struct {
  Id   string
  Name string
  // 宛先構造体として使用する場合、このフィールドを無視
  Address string `copier:"-"`
}

type Student struct {
  // フィールド名を指定
  StudentId   string `copier:"Id"`
  StudentName string `copier:"Name"`
  Address     string
  School      string
  Class       string
}

func main() {
  student := Student{
    StudentId:   "123",
    StudentName: "jack",
    Address:     "usa",
    School:      "MIT",
    Class:       "AI",
  }

  src := make(map[string]Student)
  src["a"] = student
  src["b"] = student

  dest := make(map[string]User)

  if err := copier.Copy(&dest, &src); err != nil {
    panic(err)
  }
  fmt.Printf("%+v\n", src)
  fmt.Printf("%+v\n", dest)
}

出力

map[a:{StudentId:123 StudentName:jack Address:usa School:MIT Class:AI} b:{StudentId:123 StudentName:jack Address:usa School:MIT Class:AI}]
map[a:{Id:123 Name:jack Address:} b:{Id:123 Name:jack Address:}]

カスタマイズ

copier.TypeConverter を渡すことで、変換方法をカスタマイズすることもできます

go
type TypeConverter struct {
  SrcType interface{}
  DstType interface{}
  Fn      func(src interface{}) (dst interface{}, err error)
}

以下のように

go
type User struct {
  Id   string
  Name string
  // 宛先構造体として使用する場合、このフィールドを無視
  Address string `copier:"-"`
}

type Student struct {
  // フィールド名を指定
  StudentId   string `copier:"Id"`
  StudentName string `copier:"Name"`
  Address     string
  School      string
  Class       string
}

func main() {
  student := Student{
    StudentId:   "123",
    StudentName: "jack",
    Address:     "usa",
    School:      "MIT",
    Class:       "AI",
  }

  src := make(map[string]Student)
  src["a"] = student
  src["b"] = student

  dest := make(map[string]User)

  if err := copier.CopyWithOption(&dest, &src, copier.Option{
    IgnoreEmpty:   false,
    CaseSensitive: false,
    DeepCopy:      false,
    Converters: []copier.TypeConverter{
      {
        SrcType: Student{},
        DstType: User{},
        Fn: func(src interface{}) (dst interface{}, err error) {
          s, ok := src.(Student)
          if !ok {
            return User{}, errors.New("エラータイプ")
          }
          return User{
            Id: s.StudentId,
          }, nil
        },
      },
    },
    FieldNameMapping: nil,
  }); err != nil {
    panic(err)
  }
  fmt.Printf("%+v\n", src)
  fmt.Printf("%+v\n", dest)
}

出力

map[a:{StudentId:123 StudentName:jack Address:usa School:MIT Class:AI} b:{StudentId:123 StudentName:jack Address:usa School:MIT Class:AI}]
map[a:{Id:123 Name: Address:} b:{Id:123 Name: Address:}]

Golang学习网由www.golangdev.cn整理维护