Go 每日一庫之 copier

簡介

上一篇文章介紹了mergo庫的使用,mergo是用來給結構體或map賦值的。mergo有一個明顯的不足——它只能處理相同類型的結構!若是類型不一樣,即便字段名和類型徹底相同,mergo也無能爲力。今天咱們要介紹的copier庫就能處理不一樣類型之間的賦值。除此以外,copier還能:git

  • 調用同名方法爲字段賦值;
  • 以源對象字段爲參數調用目標對象的方法,從而爲目標對象賦值(固然也能夠作其它的任何事情);
  • 將切片賦值給切片(能夠是不一樣類型哦);
  • 將結構體追加到切片中。

感謝@thinkgos推薦。github

順帶一提,做者是國人jinzhu大佬,若是你想找一個 Go 語言的 ORM 庫,gorm你值得擁有!golang

快速使用

先安裝:微信

$ go get github.com/jinzhu/copier
複製代碼

後使用:app

package main

import (
  "fmt"

  "github.com/jinzhu/copier"
)

type User struct {
  Name string
  Age  int
}

type Employee struct {
  Name string
  Age  int
  Role string
}

func main() {
  user := User{Name: "dj", Age: 18}
  employee := Employee{}

  copier.Copy(&employee, &user)
  fmt.Printf("%#v\n", employee)
}
複製代碼

很好理解,就是將user對象中的字段賦值到employee的同名字段中。若是目標對象中沒有同名的字段,則該字段被忽略。函數

高級特性

方法賦值

目標對象中的一些字段,源對象中沒有,可是源對象有同名的方法。這時Copy會調用這個方法,將返回值賦值給目標對象中的字段:學習

type User struct {
  Name string
  Age  int
}

func (u *User) DoubleAge() int {
  return 2 * u.Age
}

type Employee struct {
  Name      string
  DoubleAge int
  Role      string
}

func main() {
  user := User{Name: "dj", Age: 18}
  employee := Employee{}

  copier.Copy(&employee, &user)
  fmt.Printf("%#v\n", employee)
}
複製代碼

咱們給User添加一個DoubleAge方法。Employee結構有字段DoubleAgeUser中沒有,可是User有一個同名的方法,這時Copy調用userDoubleAge方法爲employeeDoubleAge賦值,獲得 36。spa

調用目標方法

有時候源對象中的某個字段沒有出如今目標對象中,可是目標對象有一個同名的方法,方法接受一個同類型的參數,這時Copy會以源對象的這個字段做爲參數調用目標對象的該方法:code

type User struct {
  Name string
  Age  int
  Role string
}

type Employee struct {
  Name      string
  Age       int
  SuperRole string
}

func (e *Employee) Role(role string) {
  e.SuperRole = "Super" + role
}

func main() {
  user := User{Name: "dj", Age: 18, Role: "Admin"}
  employee := Employee{}

  copier.Copy(&employee, &user)
  fmt.Printf("%#v\n", employee)
}
複製代碼

咱們給Employee添加了一個Role方法,User的字段Role沒有出如今Employee中,可是Employee有一個同名方法。Copy函數內部會以user對象的Role字段爲參數調用employeeRole方法。最終,咱們的employee對象的SuperRole值變爲SuperAdmin。實際上,這個方法中能夠執行任何操做,不必定是賦值。orm

切片賦值

使用一個切片來爲另外一個切片賦值。若是類型相同,那好辦,直接append就行。若是類型不一樣呢?copier就派上大用場了:

type User struct {
  Name string
  Age  int
}

type Employee struct {
  Name string
  Age  int
  Role string
}

func main() {
  users := []User{
    {Name: "dj", Age: 18},
    {Name: "dj2", Age: 18},
  }
  employees := []Employee{}

  copier.Copy(&employees, &users)
  fmt.Printf("%#v\n", employees)
}
複製代碼

這個實際上就是將源切片中每一個元素分別賦值到目標切片中。

將結構賦值到切片

這個不難,實際上就是根據源對象生成一個和目標切片類型相符合的對象,而後append到目標切片中:

type User struct {
  Name string
  Age  int
}

type Employee struct {
  Name string
  Age  int
  Role string
}

func main() {
  user := User{Name: "dj", Age: 18}
  employees := []Employee{}

  copier.Copy(&employees, &user)
  fmt.Printf("%#v\n", employees)
}
複製代碼

上面代碼中,Copy先經過user生成一個Employee對象,而後append到切片employees中。

彙總

最後將全部的特性彙總在一個例子中,其實就是Copier的 GitHub 倉庫首頁的例子:

type User struct {
  Name string
  Age  int
  Role string
}

func (u *User) DoubleAge() int {
  return u.Age * 2
}

type Employee struct {
  Name      string
  Age       int
  SuperRole string
}

func (e *Employee) Role(role string) {
  e.SuperRole = "Super" + role
}

func main() {
  var (
    user  = User{Name: "dj", Age: 18}
    users = []User{
      {Name: "dj", Age: 18, Role: "Admin"},
      {Name: "dj2", Age: 18, Role: "Dev"},
    }
    employee  = Employee{}
    employees = []Employee{}
  )

  copier.Copy(&employee, &user)
  fmt.Printf("%#v\n", employee)

  copier.Copy(&employees, &user)
  fmt.Printf("%#v\n", employees)

  // employees = []Employee{}

  copier.Copy(&employees, &users)
  fmt.Printf("%#v\n", employees)
}
複製代碼

上面例子中,我故意把employees = []Employee{}這一行註釋掉,最後輸出的employees是 3 個元素,能更清楚的看出切片到切片是append的,目標切片原來的元素仍是保留的。

總結

copier庫的代碼量很小,用了不到 200 行的代碼就實現瞭如此實用的一個功能,很是值得一看!

你們若是發現好玩、好用的 Go 語言庫,歡迎到 Go 每日一庫 GitHub 上提交 issue😄

參考

  1. copier GitHub:github.com/jinzhu/copi…
  2. Go 每日一庫 GitHub:github.com/darjun/go-d…

個人博客

歡迎關注個人微信公衆號【GoUpUp】,共同窗習,一塊兒進步~

相關文章
相關標籤/搜索