В разработке часто используются различные объекты, которые называются Javabeans в Java и структуры в Go. При использовании структуры ORM класс сущностей часто используется для сопоставления таблицы данных, но на самом деле объект класса сущностей сопоставленной таблицы данных редко используется непосредственно для передачи на каждом уровне, и больше других объектов (таких как DTO, VO и т. д.) Отфильтруйте или добавьте свойства считываемого объекта класса сущностей.
Друзья, которые используют Java, знают, что есть удобный инструмент под названием BeanUtils, назовите егоcopy()
метод для удаления множества операций установки. Go поставляется со многими пакетами, но нет никакого метода копирования, встроенныйcopy()
Также можно копировать только фрагменты.
Однако Go поставляется с пакетом отражения, с помощью которого мы можем вручную реализовать функцию или метод, копирующий свойство любого типа.
Он также очень прост в реализации.Друзья, которые любят поразмышлять, могут непосредственно прочитать отраженный документ и реализовать его самостоятельно.
golang.org/pkg/reflect…
Overview
Следующее взято из документации
Package reflect implements run-time reflection, allowing a program to manipulate objects with arbitrary types. The typical use is to take a value with static type interface{} and extract its dynamic type information by calling TypeOf, which returns a Type.
A call to ValueOf returns a Value representing the run-time data. Zero takes a Type and returns a Value representing a zero value for that type.
Грубо говоря, используя отражение, вы можете обрабатывать произвольные типы во время выполнения. пройти черезTypeOf
Метод получает информацию о типе, завернутую вType
середина. пройти черезValueOf
Получить данные времени выполнения, завернутые вValue
середина.
Представьте нижеreflect
Некоторые типы и методы в пакете. Те, кто уже знаком с пакетом отражения, могут сразу перейти к концу.
Kind
определение:type Kind uint
использоватьiota
определить сериюKind
Константа, представляющая тип обрабатываемого типа. Звучит запутанно, но на самом деле это очень легко понять.Помимо основных типов, когда мы настраиваем структуру,Kind
заStrcut
, когда обрабатываемый тип является указателем,Kind
заPtr
и другие, такие какSlice
,Map
,Arrray
,Chan
Ждать.
существуетValue
иType
Некоторые из методов можно использовать только для определенных типов, таких какType
изMapOf()
метод, толькоMap
использовать, когда используетсяType
нетMap
разpanic
. Таких методов гораздо больше, потому что при несовпадении типа будет напрямуюpanic()
, чтобы быть в безопасности, вы должны сначала проверитьKind
вынести приговор.
Type
ОпределенныйType
Это тип интерфейса.После получения экземпляра вы можете получить информацию о типе, вызвав серию методов.reflect.TypeOf(i interface{})
Получите экземпляр.
пройти черезName()
метод для получения имени типа.Kind()
способ получить типKind
.
еслиKind
является структурным типомStruct
,пройти черезNumField()
Можно получить количество атрибутов структуры, которые можно получить черезField(i int) StructField
,FieldByName(name string) StructField
Получите определенные свойства, возвращаемое значение является другим определенным типом структурыStructField
.
еслиKind
заArray
, Chan
, Map
, Ptr
, Slice
, доступен черезElem()
получить определенный элементType
.
Некоторые специальные методы можно использовать только для определенных типов.panic()
.
дваType
сопоставимы, вы можете использовать == или != .
StructField
Используется для описания одного свойства в структуре, определяемой следующим образом
type StructField struct {
Name string
PkgPath string
Type Type
Tag StructTag
Offset uintptr
Index []int
Anonymous bool
}
вName
имя свойства,PkgPath
путь к пакету,Type
информация о типе атрибута,Tag
Для метки (обычно используется для решения проблем с кодированием и декодированием, заинтересованные друзья могут посмотреть соответствующие библиотеки и исходный код).
Value
когда используешьType
Когда мы можем получить только соответствующую информацию о типе.Если нам нужно манипулировать конкретным значением, мы должны использоватьValue
,пройти черезreflect.ValueOf(i interface{})
. иType
разные,Value
Тип — структура.Value
также следоватьType
подобные методы, такие какNumField()
,Field(i)
,FieldByName(name string)
,Elem()
Ждать.
такжеValue
Существует также ряд методов установки, если значение может быть установлено, то мы можем динамически изменить значение.
иType
разные,Value
Сравнение не может быть выполнено с помощью == или != и должно сравниваться соответствующим методом.
Точно так же некоторые специальные методы можно использовать только для определенных типов.panic()
.
упражняться
Вышеизложенное кратко понимает основы отражения. Думаю, многие знают, как этого добиться.
Общая идея: поскольку значение необходимо изменить, целевой параметр должен быть передан с указателем структуры, а исходный параметр может быть передан указателем или экземпляром. Пройдите все значения атрибутов копируемого типа, используйтеField(i int)
Получите один атрибут, выньтеStuctField
изName
, затем используйтеName
пройти черезFieldByName(name string)
Получить значение скопированного объекта, если приобретение прошло успешно, вызватьSet(v Value)
Динамически установить значение.
coding
func SimpleCopyProperties(dst, src interface{}) (err error) {
// 防止意外panic
defer func() {
if e := recover(); e != nil {
err = errors.New(fmt.Sprintf("%v", e))
}
}()
dstType, dstValue := reflect.TypeOf(dst), reflect.ValueOf(dst)
srcType, srcValue := reflect.TypeOf(src), reflect.ValueOf(src)
// dst必须结构体指针类型
if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
return errors.New("dst type should be a struct pointer")
}
// src必须为结构体或者结构体指针
if srcType.Kind() == reflect.Ptr {
srcType, srcValue = srcType.Elem(), srcValue.Elem()
}
if srcType.Kind() != reflect.Struct {
return errors.New("src type should be a struct or a struct pointer")
}
// 取具体内容
dstType, dstValue = dstType.Elem(), dstValue.Elem()
// 属性个数
propertyNums := dstType.NumField()
for i := 0; i < propertyNums; i++ {
// 属性
property := dstType.Field(i)
// 待填充属性值
propertyValue := srcValue.FieldByName(property.Name)
// 无效,说明src没有这个属性 || 属性同名但类型不同
if !propertyValue.IsValid() || property.Type != propertyValue.Type() {
continue
}
if dstValue.Field(i).CanSet() {
dstValue.Field(i).Set(propertyValue)
}
}
return nil
}
резюме
На данный момент мы завершили копию свойства с тем же именем. потому что использоватьreflect
мешок, вездеpanic
, поэтому вам нужно использовать функцию задержки в началеrecover
один разpanic
. При передаче параметров решите, использовать ли указатель или экземпляр для второго параметра. Следует отметить, что этот метод копирования является поверхностным копированием, другими словами, если в объекте есть другие ссылочные типы, такие какSlice
,Map
Подождите, после использования этого метода для завершения копирования содержимое атрибута ссылочного типа в исходном объекте изменилось, а также изменится содержимое соответствующего атрибута объекта.
В пакете отражения есть много интересного, и заинтересованные друзья могут обратиться к документации.
golang.org/pkg/reflect…