In diesem Artikel geht es hauptsächlich um GolangMedium Reflection, in der Hoffnung, ein neues Verständnis für Sie zu gewinnen.
Obwohl viele Menschen die Go-Sprache schon seit einer gewissen Zeit verwenden und einige sie sogar seit 1 oder 2 Jahren verwenden, sind sie sich immer noch nicht sicher, was die Reflexion in der Go-Sprache angeht, und sie sind nicht sehr sicher wenn man es benutzt. [Verwandte Empfehlungen: Go-Video-Tutorial, Programmierunterricht]
Außerdem wird fast keine Reflexion verwendet. Natürlich ist es am einfachsten und effizientesten, es bei der Arbeit zu verwenden ist skalierbar und bietet eine gute Leistung. Es ist nicht nötig, einige fortgeschrittene Anwendungen mechanisch zu kopieren. Wir können nicht viel ausprobieren von uns selbst. Lassen Sie uns dieses Mal einen genaueren Blick darauf werfen, wie man mit Reflexion spielt.
Artikel Lassen Sie uns darüber sprechen Fälle und flexible Anwendung
- Reflexionsprinzip
- Zusammenfassung
- Einfach gesagt ist Reflexion das, was
- Einfach ausgedrückt: Reflexion ist die Fähigkeit, auf das Programm selbst zuzugreifen und es zu ändern, während das Programm läuft
- Dies ist ein Mechanismus, der in der Go-Sprache bereitgestellt wird . Wir können viel über die Verwendung von Reflect in der öffentlichen Bibliothek der Go-Sprache sehen. Aber warum verwenden wir im Allgemeinen Reflexion?
Entsprechend der Reflexionsfähigkeit ist der spezifische Datentyp natürlich nur bekannt, wenn das Programm ausgeführt wird, da die von uns bereitgestellte Schnittstelle den eingehenden Datentyp nicht kennt. Aber wir erwarten ihn beim Codieren. Um zu überprüfen, was Der Typ, der beim Ausführen des Programms übergeben wird (z. B. JSON-Serialisierung) und mit diesen spezifischen Daten arbeitet, muss zu diesem Zeitpunkt die Reflexionsfähigkeit nutzen
Es ist also nicht seltsam, dass Sie bei der Verwendung die Schnittstelle sehen können {} Wo spiegelt es sich wider?
Das liegt daran, dass wir nicht sicher sind, um welchen Typ der eingehenden Daten es sich handeln wird. Deshalb haben wir ihn als Schnittstelle konzipiert{}. Wenn Sie sich über die Eigenschaften und die Verwendung der Schnittstelle nicht sicher sind, können Sie die historischen Artikel lesen:
Was sollte ich bei der Schnittstelle{} beachten?
Was sollte ich bei der Schnittstelle{} beachten? Als nächstes
Achten Sie zunächst auf die drei wichtigen Gesetze der Reflexion
wird es kein Problem geben, wenn wir nach den Regeln spielenWir kennen die Regeln nicht, es treten immer seltsame Probleme auf, wenn die Klausel ausgelöst wird.
Reflection kann Variablen vom Schnittstellentyp in Objekte vom Reflexionstyp konvertieren Wenn Sie ein Objekt vom Typ „Reflexion“ zur Laufzeit ändern möchten, muss der Wert, der diesem Objekt entspricht, beschreibbar sein. Erinnern Sie sich auch an die oben genannten Zeiger im unsicheren Paket? Wir konvertieren unsere häufig verwendeten Datentypen in bestimmte Datentypen in Paketen (z. B. unsichere Pakete oder Reflect-Pakete) und ändern dann die Daten gemäß den Regeln in den Paketen.
Es entspricht dem Wechseln einer Weste, und Sie können es Mach es Verschiedene Operationen
- Achten Sie auf die Anwendungsfälle und nutzen Sie sie flexibel Im Allgemeinen verstehen wir zuerst die grundlegende Anwendung, studieren dann ihre Prinzipien und warum sie auf diese Weise verwendet werden kann, und langsam können wir sie verstehen tiefer gehen
- Für Gesetz 1 konvertieren Sie Schnittstellentypvariablen in Reflexionstypobjekte Tatsächlich können wir für die hier erwähnten Schnittstellentypvariablen Variablen jedes Datentyps übergeben, z. B.
Unter
Reflection-Typobjekten können hier die Objekte reflect.Type
und reflect.Value
im Reflect-Paket verstanden werden, auf die über die in bereitgestellten reflect.Type
和 reflect.Value
对象,可以通过 reflect 包中提供的 TypeOf 和 ValueOf 函数得到
其中 reflect.Type
实际上是一个 interface ,他里面包含了各种接口需要进行实现,它里面提供了关于类型相关的信息
其中如下图可以查看到 reflect.Type
的所有方法,其中
- 绿色的 是所有数据类型都是可以调用的
- 红色的是 函数类型数据可以调用的
- 黑色的是 Map,数组 Array,通道 Chan,指针 Ptr 或者 切片Slice 可以调用的
- 蓝色的是结构体调用的
- 黄色的是通道 channel 类型调用的
reflect.Value
实际上是一个 struct,根据这个 struct 还关联了一组方法,这里面存放了数据类型和具体的数据,通过查看其数据结构就可以看出
type Value struct { typ *rtype ptr unsafe.Pointer flag }
看到此处的 unsafe.Pointer 是不是很熟悉,底层自然就可以将 unsafe.Pointer
转换成 uintptr
,然后再修改其数据后,再转换回来,对于 Go 指针不太熟悉的可以查看这篇文章:
写一个简单的 demo 就可以简单的获取到变量的数据类型和值
func main() { var demoStr string = "now reflect" fmt.Println("type:", reflect.TypeOf(demoStr)) fmt.Println("value:", reflect.ValueOf(demoStr)) }
对于定律二,将 反射类型的对象 转换成 接口类型的变量
我们可以通过将 reflect.Value
类型转换成我们具体的数据类型,因为 reflect.Value
中有对应的 typ *rtype
以及 ptr unsafe.Pointer
例如我们可以 通过 reflect.Value
对象的 interface() 方法来处理
func main() { var demoStr string = "now reflect" fmt.Println("type:", reflect.TypeOf(demoStr)) fmt.Println("value:", reflect.ValueOf(demoStr)) var res string res = reflect.ValueOf(demoStr).Interface().(string) fmt.Println("res == ",res) }
对于定律三,修改反射类型的对象
首先我们看上书的 demo 代码,传入 TypeOf 和 ValueOf 的变量实际上也是一个拷贝,那么如果期望在反射类型的对象中修改其值,那么就需要拿到具体变量的地址然后再进行修改,前提是这个变量是可写的
举个例子你就能明白
func main() { var demoStr string = "now reflect" v := reflect.ValueOf(demoStr) fmt.Println("is canset ", v.CanSet()) //v.SetString("hello world") // 会panic }
可以先调用 reflect.Value
对象的 CanSet
查看是否可写,如果是可写的,我们再写,如果不可写就不要写了,否则会 panic
那么传入变量的地址就可以修改了??
传入地址的思路没有毛病,但是我们去设置值的方式有问题,因此也会出现上述的 panic 情况
此处仔细看能够明白,反射的对象 v 自然是不可修改的,我们应该找到 reflect.Value
里面具体具体的数据指针,那么才是可以修改的,可以使用 reflect.Value
TypeOf und zugegriffen werden kann Das Reflect-Paket. Die ValueOf-Funktion erhält
wobei reflect.Type
tatsächlich eine Schnittstelle ist, die verschiedene Schnittstellen enthält, die implementiert werden müssen. Sie stellt Informationen über den Typ bereit, die angezeigt werden können Wie in der Abbildung unten gezeigt. Zu allen Methoden von reflect.Type
gehören die
grünen, bei denen alle Datentypen aufgerufen werden können.
- rote sind die Funktionstypdaten, die aufgerufen werden können aufgerufen werden
- Die schwarzen sind Map, Array Array, Channel Chan, Pointer Ptr oder Slice Slice, die aufgerufen werden können
werden durch die Struktur

reflect.Value
ist eigentlich eine Struktur, der auch eine Reihe von Methoden zugeordnet sind, die den Datentyp und spezifische Daten speichern. Sie können dies anhand der Datenstruktur erkennen 🎜Siehe hier: Sind Sie mit unsafe.Pointer vertraut? Die unterste Ebene kann unsafe.Pointer
natürlich in uintptr
konvertieren, dann seine Daten ändern und sie dann wieder in For Go-Zeiger konvertieren , das ist es nicht. Wenn Sie zu vertraut sind, können Sie sich diesen Artikel ansehen: 🎜🎜🎜Zeiger in GO? 🎜🎜🎜Schreiben Sie eine einfache Demo, um den Datentyp und den Wert der Variablen einfach zu erhalten🎜type RDemo struct { Name string Age int Money float32 Hobby map[string][]string } func main() { tmp := &RDemo{ Name: "xiaomiong", Age: 18, Money: 25.6, Hobby: map[string][]string{ "sport": {"basketball", "football"}, "food": {"beef"}, }, } v := reflect.ValueOf(tmp).Elem() // 拿到结构体对象 h := v.FieldByName("Hobby") // 拿到 Hobby 对象 h1 := h.MapKeys()[0] // 拿到 Hobby 的第 0 个key fmt.Println("key1 name == ",h1.Interface().(string)) sli := h.MapIndex(h1) // 拿到 Hobby 的第 0 个key对应的对象 str := sli.Index(1) // 拿到切片的第 1 个对象 fmt.Println(str.CanSet()) str.SetString("helloworld") fmt.Println("tmp == ",tmp) }🎜

🎜Konvertieren Sie für Gesetz 2 Objekte vom Reflexionstyp in Variablen vom Schnittstellentyp.🎜🎜 🎜Wir können die konvertieren reflect.Value
Typ in unseren spezifischen Datentyp, da es einen entsprechenden typ *rtype
in reflect.Value
und ptr unsicher gibt. Zeiger
🎜🎜Zum Beispiel können wir ihn über die interface()-Methode des reflect.Value
-Objekts verarbeiten🎜🎜
🎜// rtype must be kept in sync with ../runtime/type.go:/^type._type.
type rtype struct {
size uintptr
ptrdata uintptr
hash uint32
tflag tflag
align uint8
fieldAlign uint8
kind uint8
equal func(unsafe.Pointer, unsafe.Pointer) bool
gcdata *byte
str nameOff
ptrToThis typeOff
}
🎜
🎜Ändern Sie für Gesetz drei das Reflexionstypobjekt 🎜🎜Zuerst betrachten wir Im Democode im Buch handelt es sich bei den in 🎜TypeOf🎜 und 🎜ValueOf🎜 übergebenen Variablen tatsächlich um Kopien. Wenn Sie also seinen Wert in einem Reflexionstypobjekt ändern möchten, müssen Sie die Adresse der spezifischen Variablen abrufen und diese dann ändern . 🎜Die Voraussetzung ist, dass diese Variable beschreibbar ist🎜🎜🎜Sie können es anhand eines Beispiels verstehen🎜// emptyInterface is the header for an interface{} value.type emptyInterface struct {
typ *rtype
word unsafe.Pointer
}复制代码
🎜
🎜🎜Sie können zuerst das CanSet
des reflect.Value
-Objekts aufrufen, um zu überprüfen, ob es beschreibbar ist. Wenn ja , Lass es uns noch einmal schreiben. Wenn es nicht geschrieben werden kann, schreibe es nicht, sonst gerät es in Panik🎜🎜
🎜🎜Dann kann die Adresse der übergebenen Variablen geändert werden? ? 🎜🎜
🎜🎜Eingehende Adresse Es gibt An der Idee ist nichts auszusetzen, aber an der Art und Weise, wie wir den Wert festlegen, stimmt etwas nicht, sodass auch hier die oben erwähnte Paniksituation auftritt. Wenn Sie hier genau hinschauen, können Sie verstehen, dass das reflektierte Objekt v natürlich nicht veränderbar ist reflect.Value Der spezifische Datenzeiger in
kann für einen etwas komplizierteren Fall geändert werden , Sie denken vielleicht, dass es sich um einen so einfachen Fall handelt und dass er in Ordnung sein wird, sobald er demonstriert wird, aber er wird abstürzen, sobald er bei der Arbeit verwendet wird. Natürlich ist er noch nicht vollständig verstanden, was bedeutet, dass dies der Fall ist Es wurde nicht gut verdaut. Hier ist ein weiteres Beispiel bei der Arbeit: Eine Struktur hat eine Karte, der Schlüssel in der Karte ist ein String und der Wert ist [] String. Die Anforderung besteht darin, auf den 🎜1🎜 zuzugreifen Element des Slice, das dem Hobby-Feld in der Struktur entspricht, mit dem Kartenschlüssel 🎜sport🎜 und ändern Sie es in 🎜 hellolworld🎜🎜🎜rrreee🎜🎜🎜
// emptyInterface is the header for an interface{} value.type emptyInterface struct { typ *rtype word unsafe.Pointer }复制代码🎜

CanSet
des reflect.Value
-Objekts aufrufen, um zu überprüfen, ob es beschreibbar ist. Wenn ja , Lass es uns noch einmal schreiben. Wenn es nicht geschrieben werden kann, schreibe es nicht, sonst gerät es in Panik🎜🎜

reflect.Value Der spezifische Datenzeiger in
kann für einen etwas komplizierteren Fall geändert werden , Sie denken vielleicht, dass es sich um einen so einfachen Fall handelt und dass er in Ordnung sein wird, sobald er demonstriert wird, aber er wird abstürzen, sobald er bei der Arbeit verwendet wird. Natürlich ist er noch nicht vollständig verstanden, was bedeutet, dass dies der Fall ist Es wurde nicht gut verdaut. Hier ist ein weiteres Beispiel bei der Arbeit: Eine Struktur hat eine Karte, der Schlüssel in der Karte ist ein String und der Wert ist [] String. Die Anforderung besteht darin, auf den 🎜1🎜 zuzugreifen Element des Slice, das dem Hobby-Feld in der Struktur entspricht, mit dem Kartenschlüssel 🎜sport🎜 und ändern Sie es in 🎜 hellolworld🎜🎜🎜rrreee🎜🎜🎜可以看到上述案例运行之后有时可以运行成功,有时会出现 panic 的情况,相信细心的 xdm 就可以看出来,是因为 map 中的 key 是 无序的导致的,此处也提醒一波,使用 map 的时候要注意这一点
看上述代码,是不是就能够明白咱们使用反射去找到对应的数据类型,然后按照数据类型进行处理数据的过程了呢
有需要的话,可以慢慢的去熟练反射包中涉及的函数,重点是要了解其三个规则,对象转换方式,访问方式,以及数据修改方式
反射原理
那么通过上述案例,可以知道关于反射中数据类型和数据指针对应的值是相当重要的,不同的数据类型能够用哪些函数这个需要注意,否则用错直接就会 panic
TypeOf
来看 TypeOf 的接口中涉及的数据结构
在 reflect 包中 rtype
是非常重要的,Go 中所有的类型都会包含这个结构,所以咱们反射可以应用起来,结构如下
// rtype must be kept in sync with ../runtime/type.go:/^type._type. type rtype struct { size uintptr ptrdata uintptr hash uint32 tflag tflag align uint8 fieldAlign uint8 kind uint8 equal func(unsafe.Pointer, unsafe.Pointer) bool gcdata *byte str nameOff ptrToThis typeOff }
其中可以看到此处的 rtype
的结构保持和 runtime/type.go
一致 ,都是关于数据类型的表示,以及对应的指针,关于这一块的说明和演示可以查看文末的 interface{} 处的内容
ValueOf
从 ValueOf 的源码中,我们可以看到,重要的是 emptyInterface 结构
// emptyInterface is the header for an interface{} value.type emptyInterface struct { typ *rtype word unsafe.Pointer }复制代码
emptyInterface 结构中有 rtype
类型的指针, word 自然是对应的数据的地址了
reflect.Value
对象中的方法也是非常的多,用起来和上述说到的 reflect.Type
接口中的功能类似
关于源码中涉及到的方法,就不再过多的赘述了,更多的还是需要自己多多实践才能体会的更好
殊不知,此处的 reflect.Value
也是可以转换成 reflect.Type
,可以查看源码中 reflect\value.go
的 func (v Value) Type() Type {
其中 reflect.Value
,reflect.Type
,和任意数据类型
可以相互这样来转换
如下图:
总结
至此,关于反射就聊到这里,一些关于源码的细节并没有详细说,更多的站在一个使用者的角度去看反射需要注意的点
关于反射,大多的人是建议少用,因为是会影响到性能,不过如果不太关注这一点,那么用起来还是非常方便的
高级功能自然也是双刃剑,你用不好就会 panic,如果你期望去使用他,那么就去更多的深入了解和一步一步的吃透他吧
大道至简,反射三定律,活学活用
更多编程相关知识,请访问:编程视频!!
Das obige ist der detaillierte Inhalt vonEin Artikel, der die Reflexion in Golang im Detail erklärt. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Golang eignet sich besser für hohe Parallelitätsaufgaben, während Python mehr Vorteile bei der Flexibilität hat. 1. Golang behandelt die Parallelität effizient über Goroutine und Kanal. 2. Python stützt sich auf Threading und Asyncio, das von GIL betroffen ist, jedoch mehrere Parallelitätsmethoden liefert. Die Wahl sollte auf bestimmten Bedürfnissen beruhen.

Die Leistungsunterschiede zwischen Golang und C spiegeln sich hauptsächlich in der Speicherverwaltung, der Kompilierungsoptimierung und der Laufzeiteffizienz wider. 1) Golangs Müllsammlung Mechanismus ist praktisch, kann jedoch die Leistung beeinflussen.

Wählen SieGolangforHighperformanceConcurcurrency, idealforbackendServicesandNetworkProgramming; selectPythonforrapidDevelopment, DataScience und MachinelearningDuEToSverseStilityAntenSiveselibrary.

Golang und Python haben jeweils ihre eigenen Vorteile: Golang ist für hohe Leistung und gleichzeitige Programmierung geeignet, während Python für Datenwissenschaft und Webentwicklung geeignet ist. Golang ist bekannt für sein Parallelitätsmodell und seine effiziente Leistung, während Python für sein Ökosystem für die kurze Syntax und sein reiches Bibliothek bekannt ist.

In welchen Aspekten sind Golang und Python einfacher zu verwenden und haben eine glattere Lernkurve? Golang eignet sich besser für hohe Parallelitäts- und hohe Leistungsbedürfnisse, und die Lernkurve ist für Entwickler mit C -Sprachhintergrund relativ sanft. Python eignet sich besser für Datenwissenschaft und schnelles Prototyping, und die Lernkurve ist für Anfänger sehr reibungslos.

Golang und C haben jeweils ihre eigenen Vorteile bei Leistungswettbewerben: 1) Golang ist für eine hohe Parallelität und schnelle Entwicklung geeignet, und 2) C bietet eine höhere Leistung und eine feinkörnige Kontrolle. Die Auswahl sollte auf Projektanforderungen und Teamtechnologie -Stack basieren.

Golang eignet sich für eine schnelle Entwicklung und gleichzeitige Programmierung, während C für Projekte, die eine extreme Leistung und die zugrunde liegende Kontrolle erfordern, besser geeignet sind. 1) Golangs Parallelitätsmodell vereinfacht die Parallelitätsprogrammierung durch Goroutine und Kanal. 2) Die Vorlagenprogrammierung von C bietet generische Code und Leistungsoptimierung. 3) Golangs Müllsammlung ist bequem, kann jedoch die Leistung beeinflussen. Die Speicherverwaltung von C ist komplex, aber die Kontrolle ist in Ordnung.

GoimpactsDevelopmentPositivyThroughSpeed, Effizienz und DiasMlitication.1) Geschwindigkeit: Gocompilesquickandrunseffiction, idealforlargeProjects


Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

Heiße Werkzeuge

WebStorm-Mac-Version
Nützliche JavaScript-Entwicklungstools

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

EditPlus chinesische Crack-Version
Geringe Größe, Syntaxhervorhebung, unterstützt keine Code-Eingabeaufforderungsfunktion

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

VSCode Windows 64-Bit-Download
Ein kostenloser und leistungsstarker IDE-Editor von Microsoft