Three laws of reflection: 1. Reflection can convert "interface type variables" into "reflection type objects", where the reflection type refers to "reflect.Type" and "reflect.Value"; 2. Reflection can convert " "Reflection type object" is converted into "interface type variable"; 3. If you want to modify the "reflection type object", its value must be "writable".

The operating environment of this tutorial: Windows 7 system, GO version 1.18, Dell G3 computer.
In the world of reflection, we have the ability to obtain the type, properties and methods of an object.

Two types: Type and Value
In the world of Go reflection, there are two types that are very important and are the basis for the entire The core of reflection, when learning how to use the reflect package, you must first learn these two types:
reflect.Type
reflect. Value
They correspond to type and value in the real world respectively, but in the reflection object, they have more content.
From the source code point of view, reflect.Type exists in the form of an interface
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
}and reflect.Value exists in the form of a structure,
type Value struct {
typ *rtype
ptr unsafe.Pointer
flag
}At the same time It accepts a lot of methods (see the table below), and due to space limitations, there is no way to introduce them one by one here.
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
Through the content of the previous section (), we know that an interface variable is actually composed of a pair (type and data). The pair records the value and value of the actual variable. type. That is to say, in the real world, type and value are combined to form interface variables.
In the world of reflection, type and data are separated, and they are represented by reflect.Type and reflect.Value respectively.
Interpretation of the Three Laws of Reflection
There is a Three Laws of Reflection in the Go language, which is a very important reference when you are learning reflection:
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.
Translated, it is:
Reflection can convert "interface type variable" to "Reflection type object";
Reflection can convert "reflection type object" into "interface type variable";
If you want to modify" Reflection type object" its type must be "writable";
First Law
Reflection goes from interface value to reflection object.
In order to realize the conversion from interface variables to reflection objects, two very important methods in the reflect package need to be mentioned:
reflect. TypeOf(i): Get the type of the interface value
reflect.ValueOf(i): Get the value of the interface value
These two methods The returned objects are called reflection objects: Type object and Value object.

For example, let’s see how these two methods are used?
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)
}The output is as follows
原始接口变量的类型为 int,值为 25 从接口变量到反射对象:Type对象的类型为 *reflect.rtype 从接口变量到反射对象:Value对象的类型为 reflect.Value 复制代码
In this way, we have completed the conversion from interface type variables to reflection objects.
Wait a minute, isn’t the age we defined above an int type? How come it is said to be an interface type in the first rule?
Regarding this point, in fact, it has been mentioned in the previous section (Three "hidden rules" about interfaces). Since the two functions TypeOf and ValueOf receive interface{ } Empty interface type, and Go language functions are all passed by value, so Go language will implicitly convert our type into an interface type.
原始接口变量的类型为 int,值为 25 从接口变量到反射对象:Type对象的类型为 *reflect.rtype 从接口变量到反射对象:Value对象的类型为 reflect.Value
Second Law
Reflection goes from reflection object to interface value.
Just the opposite of the first law, The second law describes the conversion from reflected objects to interface variables.

It can be seen from the source code that the structure of reflect.Value will receive the Interface method and return a variable of type interface{} (Note: Only Value can be reverse-converted, but Type cannot. This is also easy to understand. If Type can be reverse-converted, what can it be reverse-converted into? )
// 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)
}This function is what we use To implement a bridge that converts reflection objects into interface variables.
Examples are as follows
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
知道了如何使反射的世界里的对象具有可写性后,接下来是时候了解一下如何对修改更新它。
反射对象,都会有如下几个以 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编程时光
The above is the detailed content of What are the three laws of reflection in go language. For more information, please follow other related articles on the PHP Chinese website!
Golang and Python: Understanding the DifferencesApr 18, 2025 am 12:21 AMThe main differences between Golang and Python are concurrency models, type systems, performance and execution speed. 1. Golang uses the CSP model, which is suitable for high concurrent tasks; Python relies on multi-threading and GIL, which is suitable for I/O-intensive tasks. 2. Golang is a static type, and Python is a dynamic type. 3. Golang compiled language execution speed is fast, and Python interpreted language development is fast.
Golang vs. C : Assessing the Speed DifferenceApr 18, 2025 am 12:20 AMGolang is usually slower than C, but Golang has more advantages in concurrent programming and development efficiency: 1) Golang's garbage collection and concurrency model makes it perform well in high concurrency scenarios; 2) C obtains higher performance through manual memory management and hardware optimization, but has higher development complexity.
Golang: A Key Language for Cloud Computing and DevOpsApr 18, 2025 am 12:18 AMGolang is widely used in cloud computing and DevOps, and its advantages lie in simplicity, efficiency and concurrent programming capabilities. 1) In cloud computing, Golang efficiently handles concurrent requests through goroutine and channel mechanisms. 2) In DevOps, Golang's fast compilation and cross-platform features make it the first choice for automation tools.
Golang and C : Understanding Execution EfficiencyApr 18, 2025 am 12:16 AMGolang and C each have their own advantages in performance efficiency. 1) Golang improves efficiency through goroutine and garbage collection, but may introduce pause time. 2) C realizes high performance through manual memory management and optimization, but developers need to deal with memory leaks and other issues. When choosing, you need to consider project requirements and team technology stack.
Golang vs. Python: Concurrency and MultithreadingApr 17, 2025 am 12:20 AMGolang is more suitable for high concurrency tasks, while Python has more advantages in flexibility. 1.Golang efficiently handles concurrency through goroutine and channel. 2. Python relies on threading and asyncio, which is affected by GIL, but provides multiple concurrency methods. The choice should be based on specific needs.
Golang and C : The Trade-offs in PerformanceApr 17, 2025 am 12:18 AMThe performance differences between Golang and C are mainly reflected in memory management, compilation optimization and runtime efficiency. 1) Golang's garbage collection mechanism is convenient but may affect performance, 2) C's manual memory management and compiler optimization are more efficient in recursive computing.
Golang vs. Python: Applications and Use CasesApr 17, 2025 am 12:17 AMChooseGolangforhighperformanceandconcurrency,idealforbackendservicesandnetworkprogramming;selectPythonforrapiddevelopment,datascience,andmachinelearningduetoitsversatilityandextensivelibraries.
Golang vs. Python: Key Differences and SimilaritiesApr 17, 2025 am 12:15 AMGolang and Python each have their own advantages: Golang is suitable for high performance and concurrent programming, while Python is suitable for data science and web development. Golang is known for its concurrency model and efficient performance, while Python is known for its concise syntax and rich library ecosystem.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

PhpStorm Mac version
The latest (2018.2.1) professional PHP integrated development tool

SAP NetWeaver Server Adapter for Eclipse
Integrate Eclipse with SAP NetWeaver application server.

SublimeText3 English version
Recommended: Win version, supports code prompts!

Atom editor mac version download
The most popular open source editor

Dreamweaver Mac version
Visual web development tools







