Привет всем, меня зовут Мин.
В период самостоятельного изучения Golang я написал подробные учебные заметки и разместил их в своем личном общедоступном аккаунте WeChat «Время программирования на Go».Что касается языка Go, я тоже новичок, поэтому то, что я написал, должно больше подходить для новых студентов, если вы только изучаете язык Go, вам стоит обратить на него внимание, учиться и расти вместе.
Мой онлайн-блог:golang.iswbm.com
Мой Github: github.com/iswbm/GolangCodingTime
Когда я использую Python, я даже могу сразу делать что-то с самоанализом, не зная, что такое самоанализ и что такое рефлексия.
После изучения языка Go для меня стало трудным моментом рефлексия, и я всегда чувствовал этообъект отраженияКонцепция необычной абстракции.
Эта статья будет такой же, как и предыдущая статья, попробуйте использовать диаграммы для объяснения некоторых абстрактных понятий, если я ошибаюсь, я надеюсь, что вы оставите сообщение в конце статьи, чтобы исправить меня, спасибо.
Что касается содержания рефлексии, то я разделил ее на несколько статей, эта статья является вводной, я начну с классических трех законов рефлексии, напишу несколько демо-кодов и расскажу основное содержание рефлексии.
1. Реальный мир и отраженный мир
В этой статье, чтобы различать типы значений переменных до и после отражения, я называю среду до отраженияреальный мир, а отраженная среда называетсямир отражения. Эта аналогия не является строгой, но она полезна для моего понимания, и я надеюсь, что она будет полезна и вам.
В мире отражения у нас есть возможность получить тип, свойства и методы объекта.
2. Два типа: тип и значение
В мире отражения Go есть два типа, которые очень важны и являются ядром всего отражения.При изучении использования пакета Reflect вы должны сначала изучить эти два типа:
- reflect.Type
- reflect.Value
Они соответствуют типу и значению в реальном мире, но в объекте отражения имеют больше содержания.
С точки зрения исходного кода, Reflect.Type существует в виде интерфейса.
type Type interface {
Align() int
FieldAlign() int
Method(int) Method
MethodByName(string) (Method, bool)
NumMethod() int
Name() string
PkgPath() string
Size() uintptr
String() string
Kind() Kind
Implements(u Type) bool
AssignableTo(u Type) bool
ConvertibleTo(u Type) bool
Comparable() bool
Bits() int
ChanDir() ChanDir
IsVariadic() bool
Elem() Type
Field(i int) StructField
FieldByIndex(index []int) StructField
FieldByName(name string) (StructField, bool)
FieldByNameFunc(match func(string) bool) (StructField, bool)
In(i int) Type
Key() Type
Len() int
NumField() int
NumIn() int
NumOut() int
Out(i int) Type
common() *rtype
uncommon() *uncommonType
}
И Reflect.Value существует в виде структуры,
type Value struct {
typ *rtype
ptr unsafe.Pointer
flag
}
В то же время он допускает множество методов (см. таблицу ниже), которые не могут быть здесь представлены из-за нехватки места.
Addr
Bool
Bytes
runes
CanAddr
CanSet
Call
CallSlice
call
Cap
Close
Complex
Elem
Field
FieldByIndex
FieldByName
FieldByNameFunc
Float
Index
Int
CanInterface
Interface
InterfaceData
IsNil
IsValid
IsZero
Kind
Len
MapIndex
MapKeys
MapRange
Method
NumMethod
MethodByName
NumField
OverflowComplex
OverflowFloat
OverflowInt
OverflowUint
Pointer
Recv
recv
Send
send
Set
SetBool
SetBytes
setRunes
SetComplex
SetFloat
SetInt
SetLen
SetCap
SetMapIndex
SetUint
SetPointer
SetString
Slice
Slice3
String
TryRecv
TrySend
Type
Uint
UnsafeAddr
assignTo
Convert
Из содержания предыдущего раздела ( ) мы знаем, что переменная интерфейса на самом деле состоит из пары (тип и данные), которая записывает значение и тип фактической переменной. Другими словами, в реальном мире тип и значение объединяются в переменные интерфейса.
В мире отражений тип и данные разделены и представлены соответственно Reflect.Type и Reflect.Value.
3. Интерпретируйте три закона отражения
В языке Go есть три закона рефлексии, которые являются важной ссылкой, когда вы изучаете рефлексию:
- Reflection goes from interface value to reflection object.
- Reflection goes from reflection object to interface value.
- To modify a reflection object, the value must be settable.
В переводе это:
- Отражение может преобразовывать переменные типа интерфейса в «объекты типа отражения»;
- Отражение может преобразовывать «объекты типа отражения» в переменные типа интерфейса;
- Если вы хотите изменить «объект типа отражения», его тип должен быть доступен для записи;
первый закон
Reflection goes from interface value to reflection object.
Чтобы реализовать преобразование из переменных интерфейса в объекты отражения, необходимо упомянуть два важных метода в пакете отражения:
- Reflect.TypeOf(i): получить тип значения интерфейса
- Reflect.ValueOf(i): получить значение значения интерфейса
Объекты, возвращаемые этими двумя методами, называются объектами отражения: объект Type и объект Value.
Например, посмотрите, как используются эти два метода?
package main
import (
"fmt"
"reflect"
)
func main() {
var age interface{} = 25
fmt.Printf("原始接口变量的类型为 %T,值为 %v \n", age, age)
t := reflect.TypeOf(age)
v := reflect.ValueOf(age)
// 从接口变量到反射对象
fmt.Printf("从接口变量到反射对象:Type对象的类型为 %T \n", t)
fmt.Printf("从接口变量到反射对象:Value对象的类型为 %T \n", v)
}
Вывод выглядит следующим образом
原始接口变量的类型为 int,值为 25
从接口变量到反射对象:Type对象的类型为 *reflect.rtype
从接口变量到反射对象:Value对象的类型为 reflect.Value
Вот мы и завершили преобразование из переменной типа интерфейса в объект отражения.
Подождите, разве возраст, который мы определили выше, не имеет тип int? Как первый закон может сказать, что это тип интерфейса?
В связи с этим, собственно, в предыдущем разделе (Три «скрытых правила» об интерфейсах) уже упоминалось, так как функции TypeOf и ValueOf получают пустой тип интерфейса interface{}, а функции языка Go передаются по значению, язык Go будет неявно преобразовывать наши типы в типы интерфейса.
// TypeOf returns the reflection Type of the value in the interface{}.TypeOf returns nil.
func TypeOf(i interface{}) Type
// ValueOf returns a new Value initialized to the concrete value stored in the interface i. ValueOf(nil) returns the zero Value.
func ValueOf(i interface{}) Value
второй закон
Reflection goes from reflection object to interface value.
Вопреки первому закону, второй закон описывает преобразование отражающих объектов в интерфейсные переменные.
Из исходного кода видно, что структура Reflect.Value получаетInterfaceметод, который возвращаетinterface{}переменная типа (Примечание. Только значение можно обратить, а тип нельзя. Это также легко понять. Если тип можно обратить, что можно изменить?)
// Interface returns v's current value as an interface{}.
// It is equivalent to:
// var i interface{} = (v's underlying value)
// It panics if the Value was obtained by accessing
// unexported struct fields.
func (v Value) Interface() (i interface{}) {
return valueInterface(v, true)
}
Эта функция является мостом, который мы используем для преобразования объекта отражения в переменную интерфейса.
Примеры следующие
package main
import (
"fmt"
"reflect"
)
func main() {
var age interface{} = 25
fmt.Printf("原始接口变量的类型为 %T,值为 %v \n", age, age)
t := reflect.TypeOf(age)
v := reflect.ValueOf(age)
// 从接口变量到反射对象
fmt.Printf("从接口变量到反射对象:Type对象的类型为 %T \n", t)
fmt.Printf("从接口变量到反射对象:Value对象的类型为 %T \n", v)
// 从反射对象到接口变量
i := v.Interface()
fmt.Printf("从反射对象到接口变量:新对象的类型为 %T 值为 %v \n", i, i)
}
Вывод выглядит следующим образом
原始接口变量的类型为 int,值为 25
从接口变量到反射对象:Type对象的类型为 *reflect.rtype
从接口变量到反射对象:Value对象的类型为 reflect.Value
从反射对象到接口变量:新对象的类型为 int 值为 25
Конечно, окончательный преобразованный объект имеет статический типinterface{}, если вы хотите преобразовать в исходный примитивный тип, вам нужно преобразовать утверждение типа.Я объяснил это в предыдущем разделе, вы можете щелкнуть здесь, чтобы просмотреть: ().
i := v.Interface().(int)
Пока мы изучили два закона отражения.Для понимания этих двух законов я нарисовал картинку.Вы можете использовать следующую картинку,чтобы укрепить свое понимание и облегчить себе память.
третий закон
To modify a reflection object, the value must be settable.
Отраженный мир — это «отображение» реального мира, мое описание, но это не строго, потому что не все, что вы делаете в отраженном мире, будет восстановлено в реальном мире.
Третий закон приводит кsettable(устанавливаемая или записываемая) концепция.
На самом деле, уже в предыдущих статьях мы говорили, что функции в языке Go передаются по значению, и пока вы не передаете указатель на переменную, ваше изменение переменной внутри функции не повлияет на исходная переменная.
Возвращаясь к отражению, когда вы используете Reflect.Typeof и Reflect.Valueof, если вы не передаете указатель на переменную интерфейса, значение переменной в мире отражения всегда будет просто копией реального мира, и вы изменяете объект отражения и не может быть отражен в реальном мире.
Итак, в правилах отражения
- Это не объект отражения, созданный путем получения указателя на переменную, он не имеет "Возможность записи"из
- Есть ли у него "возможность записи", быть пригодным для использования
CanSet()получить информацию - Не имеет "возможность записи』, это бессмысленно и считается незаконным, поэтому будет сообщено об ошибке.
package main
import (
"fmt"
"reflect"
)
func main() {
var name string = "Go编程时光"
v := reflect.ValueOf(name)
fmt.Println("可写性为:", v.CanSet())
}
Вывод выглядит следующим образом
可写性为: false
Чтобы сделать объекты отражения доступными для записи, необходимо отметить две вещи.
- Указатель на переменную, переданную при создании объекта отражения.
- использовать
Elem()Функция возвращает данные, на которые указывает указатель
Полный код выглядит следующим образом
package main
import (
"fmt"
"reflect"
)
func main() {
var name string = "Go编程时光"
v1 := reflect.ValueOf(&name)
fmt.Println("v1 可写性为:", v1.CanSet())
v2 := v1.Elem()
fmt.Println("v2 可写性为:", v2.CanSet())
}
Вывод выглядит следующим образом
v1 可写性为: false
v2 可写性为: true
Теперь, когда вы знаете, как сделать объект доступным для записи в отраженном мире, пришло время научиться обновлять его для внесения изменений.
Объекты Reflection будут иметь следующиеSetКак начать слово
Эти методы являются для нас точками входа для изменения значения.
привести пример
package main
import (
"fmt"
"reflect"
)
func main() {
var name string = "Go编程时光"
fmt.Println("真实世界里 name 的原始值为:", name)
v1 := reflect.ValueOf(&name)
v2 := v1.Elem()
v2.SetString("Python编程时光")
fmt.Println("通过反射对象进行更新后,真实世界里 name 变为:", name)
}
Вывод выглядит следующим образом
真实世界里 name 的原始值为: Go编程时光
通过反射对象进行更新后,真实世界里 name 变为: Python编程时光
Справочная статья