Drei Gesetze der Reflexion: 1. Reflexion kann „Schnittstellentypvariablen“ in „Reflexionstypobjekte“ konvertieren, wobei sich der Reflexionstyp auf „reflect.Type“ und „reflect.Value“ bezieht. 2. Reflection kann „Reflexionstyp“ konvertieren Objekte“ In „Schnittstellentypvariable“ konvertieren; 3. Wenn Sie das „Reflexionstypobjekt“ ändern möchten, muss sein Wert „schreibbar“ sein.
Die Betriebsumgebung dieses Tutorials: Windows 7-System, GO Version 1.18, Dell G3-Computer.
In der Welt der Reflexion haben wir die Fähigkeit, die Art, Eigenschaften und Methoden eines Objekts zu ermitteln.
In der Welt der Go-Reflexion gibt es zwei Typen, die sehr wichtig sind und den Kern der gesamten Reflexion bilden. Wenn Sie lernen, das Reflect-Paket zu verwenden, müssen Sie zuerst lernen Lernen Sie diese beiden Typen:
reflect.Type
reflect.Value
Sie entsprechen Typ und Wert in der realen Welt, aber in Reflexionsobjekten haben sie mehr Inhalt.
Aus dem Quellcode besteht Reflect.Type in Form einer Schnittstelle
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 }
und Reflect.Value in Form einer Struktur,
type Value struct { typ *rtype ptr unsafe.Pointer flag }
Gleichzeitig erhält es viele Methoden (siehe Tabelle). unten) Aus Platzgründen ist es nicht möglich, sie hier einzeln vorzustellen.
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
Durch den Inhalt des vorherigen Abschnitts () wissen wir, dass eine Schnittstellenvariable tatsächlich aus einem Paar (Typ und Daten) besteht und das Paar den Wert und Typ der tatsächlichen Variablen aufzeichnet. Das heißt, in der realen Welt werden Typ und Wert zu Schnittstellenvariablen kombiniert.
In der Welt der Reflexion werden Typ und Daten getrennt und durch „reflect.Type“ bzw. „reflect.Value“ dargestellt.
Go Es gibt drei Reflexionsgesetze in der Sprache, die beim Erlernen der Reflexion eine sehr wichtige Referenz darstellen:
Reflexion geht vom Schnittstellenwert zum Reflexionsobjekt.
Reflection geht vom Reflexionsobjekt zum Schnittstellenwert.
Um ein Reflexionsobjekt zu ändern, muss der Wert einstellbar sein.
Reflection kann das „Reflexionstypobjekt“ in eine „Schnittstelle“ konvertieren Typvariable“;
Wenn Sie das „Reflexionstypobjekt“ ändern möchten, muss sein Typ „beschreibbar“ sein;
Das erste Gesetz
reflect: Typ des Schnittstellenwerts abrufen
reflect .ValueOf(i): Ermitteln Sie den Wert des Schnittstellenwerts
Die von diesen beiden Methoden zurückgegebenen Objekte werden als Reflexionsobjekte bezeichnet: Typobjekt und Wertobjekt.
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 复制代码
Moment mal, ist das Alter, das wir oben definiert haben, nicht vom Typ int? Wie kommt es, dass es sich in der ersten Regel um einen Schnittstellentyp handelt?
In Bezug auf diesen Punkt wurde er tatsächlich im vorherigen Abschnitt erwähnt (
Drei „versteckte Regeln“ für Schnittstellen), da die beiden Funktionen TypeOf und ValueOf den leeren Schnittstellentyp interface{} und die Go-Sprachfunktionen erhalten werden alle als Wert übergeben, sodass die Go-Sprache unsere Typen implizit in Schnittstellentypen umwandelt.
原始接口变量的类型为 int,值为 25 从接口变量到反射对象:Type对象的类型为 *reflect.rtype 从接口变量到反射对象:Value对象的类型为 reflect.Value
Reflexion geht vom Reflexionsobjekt zum Schnittstellenwert.
Hinweis: Nur Value kann umgekehrt konvertiert werden, Type jedoch nicht. Dies ist auch leicht zu verstehen. If Type kann umgekehrt werden, was wird daraus?Aus dem Quellcode ist ersichtlich, dass die Struktur von Reflect.Value Variablen vom Typ
(
)
// 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) }
Diese Funktion ist eine Brücke, die wir verwenden, um Reflexionsobjekte in Schnittstellenvariablen umzuwandeln.
Beispiele sind wie folgtpackage 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
知道了如何使反射的世界里的对象具有可写性后,接下来是时候了解一下如何对修改更新它。
反射对象,都会有如下几个以 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编程时光
Das obige ist der detaillierte Inhalt vonWas sind die drei Reflexionsgesetze in der Go-Sprache?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!