Home Backend Development Golang What is the use of golang reflection?

What is the use of golang reflection?

Apr 17, 2020 pm 02:30 PM
golang reflection

What is the use of golang reflection? The following article will introduce you to golang reflection. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to everyone.

What is the use of golang reflection?

#golang (go) is a procedural programming language that can be used for fast machine code compilation. It is a statically typed compiled language. It provides a concurrency mechanism that makes it easy to develop multi-core and networked machine-level programs. It is a fast, dynamically typed and interpreted language; it provides support for interfaces and type embedding.

Basic understanding

In Go language, most of the time the value/type/function is very straightforward, if you want, define one. You want a Struct

1

2

3

4

type Foo struct {

    A int

    B string

}

Copy after login

You want a value, you define it

1

var x Foo

Copy after login

You want a function, you define it

1

2

3

func DoSomething(f Foo) {

  fmt.Println(f.A, f.B)

}

Copy after login

But sometimes, you need Do something that can only be determined at runtime, such as getting some dictionary data from a file or the network. Or maybe you want to get some different types of data. In this case, reflection comes in handy. Reflection allows you to have the following capabilities:

  • Check type at runtime

  • Check/modify/at runtime Create values/functions/structures

In general, go's reflection revolves around three conceptsTypes, Kinds, Values. All operations on reflection are in the reflect package

Reflection’s Power

Type’s Power

First, let’s look at how to obtain the value type through reflection.

1

varType := reflect.TypeOf(var)

Copy after login

From the reflection interface, we can see that there are a lot of functions waiting for us to use. You can see it in the comments. The reflection package assumes that we know what we are going to do. For example, varType.Elem() will panic. Because Elem() only has this method for Array, Chan, Map, Ptr, or Slice. These types only have this method. Please see the test code for details. You can see examples of all reflect functions by running the following code

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

package main

import (

    "fmt"

    "reflect"

)

type FooIF interface {

    DoSomething()

    DoSomethingWithArg(a string)

    DoSomethingWithUnCertenArg(a ... string)

}

type Foo struct {

    A int

    B string

    C struct {

        C1 int

    }

}

func (f *Foo) DoSomething() {

    fmt.Println(f.A, f.B)

}

func (f *Foo) DoSomethingWithArg(a string) {

    fmt.Println(f.A, f.B, a)

}

func (f *Foo) DoSomethingWithUnCertenArg(a ... string) {

    fmt.Println(f.A, f.B, a[0])

}

func (f *Foo) returnOneResult() int {

    return 2

}

func main() {

    var simpleObj Foo

    var pointer2obj = &simpleObj

    var simpleIntArray = [3]int{1, 2, 3}

    var simpleMap = map[string]string{

        "a": "b",

    }

    var simpleChan = make(chan int, 1)

    var x uint64

    var y uint32

    varType := reflect.TypeOf(simpleObj)

    varPointerType := reflect.TypeOf(pointer2obj)

    // 对齐之后要多少容量

    fmt.Println("Align: ", varType.Align())

    // 作为结构体的`field`要对其之后要多少容量

    fmt.Println("FieldAlign: ", varType.FieldAlign())

    // 叫啥

    fmt.Println("Name: ", varType.Name())

    // 绝对引入路径

    fmt.Println("PkgPath: ", varType.PkgPath())

    // 实际上用了多少内存

    fmt.Println("Size: ", varType.Size())

    // 到底啥类型的

    fmt.Println("Kind: ", varType.Kind())

    // 有多少函数

    fmt.Println("NumMethod: ", varPointerType.NumMethod())

    // 通过名字获取一个函数

    m, success := varPointerType.MethodByName("DoSomethingWithArg")

    if success {

        m.Func.Call([]reflect.Value{

            reflect.ValueOf(pointer2obj),

            reflect.ValueOf("sad"),

        })

    }

    // 通过索引获取函数

    m = varPointerType.Method(1)

    m.Func.Call([]reflect.Value{

        reflect.ValueOf(pointer2obj),

        reflect.ValueOf("sad2"),

    })

    // 是否实现了某个接口

    fmt.Println("Implements:", varPointerType.Implements(reflect.TypeOf((*FooIF)(nil)).Elem()))

    //  看看指针多少bit

    fmt.Println("Bits: ", reflect.TypeOf(x).Bits())

    // 查看array, chan, map, ptr, slice的元素类型

    fmt.Println("Elem: ", reflect.TypeOf(simpleIntArray).Elem().Kind())

    // 查看Array长度

    fmt.Println("Len: ", reflect.TypeOf(simpleIntArray).Len())

    // 查看结构体field

    fmt.Println("Field", varType.Field(1))

    // 查看结构体field

    fmt.Println("FieldByIndex", varType.FieldByIndex([]int{2, 0}))

    // 查看结构提field

    fi, success2 := varType.FieldByName("A")

    if success2 {

        fmt.Println("FieldByName", fi)

    }

    // 查看结构体field

    fi, success2 = varType.FieldByNameFunc(func(fieldName string) bool {

        return fieldName == "A"

    })

    if success2 {

        fmt.Println("FieldByName", fi)

    }

    //  查看结构体数量

    fmt.Println("NumField", varType.NumField())

    // 查看map的key类型

    fmt.Println("Key: ", reflect.TypeOf(simpleMap).Key().Name())

    // 查看函数有多少个参数

    fmt.Println("NumIn: ", reflect.TypeOf(pointer2obj.DoSomethingWithUnCertenArg).NumIn())

    // 查看函数参数的类型

    fmt.Println("In: ", reflect.TypeOf(pointer2obj.DoSomethingWithUnCertenArg).In(0))

    // 查看最后一个参数,是否解构了

    fmt.Println("IsVariadic: ", reflect.TypeOf(pointer2obj.DoSomethingWithUnCertenArg).IsVariadic())

    // 查看函数有多少输出

    fmt.Println("NumOut: ", reflect.TypeOf(pointer2obj.DoSomethingWithUnCertenArg).NumOut())

    // 查看函数输出的类型

    fmt.Println("Out: ", reflect.TypeOf(pointer2obj.returnOneResult).Out(0))

    // 查看通道的方向, 3双向。

    fmt.Println("ChanDir: ", int(reflect.TypeOf(simpleChan).ChanDir()))

    // 查看该类型是否可以比较。不能比较的slice, map, func

    fmt.Println("Comparable: ", varPointerType.Comparable())

    // 查看类型是否可以转化成另外一种类型

    fmt.Println("ConvertibleTo: ", varPointerType.ConvertibleTo(reflect.TypeOf("a")))

    // 该类型的值是否可以另外一个类型

    fmt.Println("AssignableTo: ", reflect.TypeOf(x).AssignableTo(reflect.TypeOf(y)))

}

Copy after login

Value's Power

In addition to checking the type of a variable, you can read/write/create a new one through reflection value. But first get the reflection value type

1

refVal := reflect.ValueOf(var)

Copy after login

if you want to modify the value of the variable. You need to obtain the reflection pointer pointing to the variable. The specific reason will be explained later

1

refPtrVal := reflect.ValueOf(&var)

Copy after login

Of course you have reflect.Value, and you can easily obtain reflect.Type through the Type() method. If you want to change the value of the variable, use

1

refPtrVal.Elem().Set(newRefValue)

Copy after login

Of course the parameters of the Set method must also be reflect.Value

If you want to create a new value, use the following code

1

newPtrVal := reflect.New(varType)

Copy after login

Then use Elem().Set() to initialize the value. Of course there are a bunch of different methods for different values. I won’t write it down here. Let’s focus on the following official example

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

package main

import (

    "fmt"

    "reflect"

)

func main() {

    // swap is the implementation passed to MakeFunc.

    // It must work in terms of reflect.Values so that it is possible

    // to write code without knowing beforehand what the types

    // will be.

    swap := func(in []reflect.Value) []reflect.Value {

        return []reflect.Value{in[1], in[0]}

    }

    // makeSwap expects fptr to be a pointer to a nil function.

    // It sets that pointer to a new function created with MakeFunc.

    // When the function is invoked, reflect turns the arguments

    // into Values, calls swap, and then turns swap's result slice

    // into the values returned by the new function.

    makeSwap := func(fptr interface{}) {

        // fptr is a pointer to a function.

        // Obtain the function value itself (likely nil) as a reflect.Value

        // so that we can query its type and then set the value.

        fn := reflect.ValueOf(fptr).Elem()

        // Make a function of the right type.

        v := reflect.MakeFunc(fn.Type(), swap)

        // Assign it to the value fn represents.

        fn.Set(v)

    }

    // Make and call a swap function for ints.

    var intSwap func(int, int) (int, int)

    makeSwap(&intSwap)

    fmt.Println(intSwap(0, 1))

    // Make and call a swap function for float64s.

    var floatSwap func(float64, float64) (float64, float64)

    makeSwap(&floatSwap)

    fmt.Println(floatSwap(2.72, 3.14))

}

Copy after login

Principle

Recognize type and interface

Go is a statically typed language. Each variable has a static type, such as int, float. What is a static type? My understanding is a binary block of a certain length and explanation. For example, the same binary block 00000001 means true in the bool type. The explanation in the int type is 1. Let's take a look at the following simplest example

1

2

3

type MyInt int

var i int

var j MyInt

Copy after login

i,j are represented by the underlying type int in the memory, but in the actual coding process, They are not of the same type when compiled, and you cannot directly assign the value of i to j. Isn't it a little strange? When you execute it, the compiler will tell you that you cannot assign a value of type MyInt to a value of type int. This type is neither a class nor a Python type.

Interface is a special type that represents a collection of methods. An interface value can store any certain value as long as the value implements the interface method. interface{} is sometimes similar to Java's Object. In fact, interface consists of two parts, the actual value and the specific type of the value. This can also explain why the following code is different from other languages. For details on the principles of interface, please refer to go data structures: interfaces.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

package main

import (

    "fmt"

)

type A interface {

    x(param int)

}

type B interface {

    y(param int)

}

type AB struct {

}

func (ab *AB) x(param int) {

    fmt.Printf("%p", ab)

    fmt.Println(param)

}

func (ab *AB) y(param int) {

    fmt.Printf("%p", ab)

    fmt.Println(param)

}

func printX(a A){

    fmt.Printf("%p", a)

    a.x(2)

}

func printY(b B){

    fmt.Printf("%p", b)

    b.y(3)

}

func main() {

    var ab = new(AB)

    printX(ab)

    printY(ab)

    var aInfImpl A

    var bInfImpl B

    aInfImpl = new(AB)

    //bInfImpl = aInfImpl  会报错

    bInfImpl = aInfImpl.(B)

    bInfImpl.y(2)

}

Copy after login

Golang’s three reflection theorems

Split an interface value into a reflection object

Reflection is only used to check the interface value (Value, Type). As mentioned in the previous chapter, the two methods ValueOf and TypeOf. Through ValueOf, we can easily get Type

1

2

3

4

5

6

7

8

9

package main

import (

    "fmt"

    "reflect"

)

func main() {

    var x float64 = 3.4

    fmt.Println("type:", reflect.TypeOf(x))

}

Copy after login

. This code outputs

1

type: float64

Copy after login

. Then the question becomes, where is the interface? Just declare a float64 variable. Where does the interface come from. Yes, the answer is hidden in the TypeOf parameter

1

func TypeOf(i interface{}) Type

Copy after login

When we call reflect.TypeOf(x), x is first stored in an empty interface. Then it is passed to the function execution stack as a parameter. ** reflect.TypeOf unwraps the pair of this interface and recovers the type information **

Combines the reflection object into an interface value

就像镜面反射一样,go的反射是可逆的。给我一个reflect.Value。我们能够恢复出一个interface的值。事实上,以下函数干的事情就是将Value和Type组狠起来塞到 interface里面去。所以我们可以

1

2

y := v.Interface().(float64) // y will have type float64.

fmt.Println(y)

Copy after login

接下来就是见证奇迹的时刻。fmt.Println和fmt.Printf的参数都是interface{}。我们真正都不需要将上面例子的y转化成明确的float64。我就可以去打印他比如

1

fmt.Println(v.Interface())

Copy after login

甚至我们的interface藏着的那个type是float64。我们可以直接用占位符来打印

1

fmt.Println("Value is %7.le\n", v.Interface())

Copy after login

再重复一边,没有必要将v.Interface()的类型强转到float64;这个空的interface{}包含了concrete type。函数调用会恢复出来

要改变一个反射对象,其值必须是可设置的

第三条比较让你比较困惑。不过如果我们理解了第一条,那么这条其实非常好理解。先看一下下面这个例子

1

2

3

var x float64 = 3.4

v := reflect.ValueOf(x)

v.SetFloat(7.1) // Error: will panic.

Copy after login

如果执行这段代码,你会发现出现panic以下信息

1

panic: reflect.Value.SetFloat using unaddressable value

Copy after login

可设置性是一个好东西,但不是所有reflect.Value都有他...可以通过CanSet 函数来获取是否可设置

1

2

3

var x float64 = 3.4

v := reflect.ValueOf(x)

fmt.Println("settability of v:", v.CanSet())

Copy after login

那么到底为什么要有一个可设置性呢?可寻址才可设置,我们在用reflect.ValueOf时候,实际上是函数传值。获取x的反射对象,实际上是另外一个float64的内存的反射对象。这个时候我们再去设置该反射对象的值,没有意义。这段内存并不是你申明的那个x。

推荐学习:Golang教程

The above is the detailed content of What is the use of golang reflection?. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to safely read and write files using Golang? How to safely read and write files using Golang? Jun 06, 2024 pm 05:14 PM

Reading and writing files safely in Go is crucial. Guidelines include: Checking file permissions Closing files using defer Validating file paths Using context timeouts Following these guidelines ensures the security of your data and the robustness of your application.

How to configure connection pool for Golang database connection? How to configure connection pool for Golang database connection? Jun 06, 2024 am 11:21 AM

How to configure connection pooling for Go database connections? Use the DB type in the database/sql package to create a database connection; set MaxOpenConns to control the maximum number of concurrent connections; set MaxIdleConns to set the maximum number of idle connections; set ConnMaxLifetime to control the maximum life cycle of the connection.

Golang framework vs. Go framework: Comparison of internal architecture and external features Golang framework vs. Go framework: Comparison of internal architecture and external features Jun 06, 2024 pm 12:37 PM

The difference between the GoLang framework and the Go framework is reflected in the internal architecture and external features. The GoLang framework is based on the Go standard library and extends its functionality, while the Go framework consists of independent libraries to achieve specific purposes. The GoLang framework is more flexible and the Go framework is easier to use. The GoLang framework has a slight advantage in performance, and the Go framework is more scalable. Case: gin-gonic (Go framework) is used to build REST API, while Echo (GoLang framework) is used to build web applications.

How to save JSON data to database in Golang? How to save JSON data to database in Golang? Jun 06, 2024 am 11:24 AM

JSON data can be saved into a MySQL database by using the gjson library or the json.Unmarshal function. The gjson library provides convenience methods to parse JSON fields, and the json.Unmarshal function requires a target type pointer to unmarshal JSON data. Both methods require preparing SQL statements and performing insert operations to persist the data into the database.

How to find the first substring matched by a Golang regular expression? How to find the first substring matched by a Golang regular expression? Jun 06, 2024 am 10:51 AM

The FindStringSubmatch function finds the first substring matched by a regular expression: the function returns a slice containing the matching substring, with the first element being the entire matched string and subsequent elements being individual substrings. Code example: regexp.FindStringSubmatch(text,pattern) returns a slice of matching substrings. Practical case: It can be used to match the domain name in the email address, for example: email:="user@example.com", pattern:=@([^\s]+)$ to get the domain name match[1].

Transforming from front-end to back-end development, is it more promising to learn Java or Golang? Transforming from front-end to back-end development, is it more promising to learn Java or Golang? Apr 02, 2025 am 09:12 AM

Backend learning path: The exploration journey from front-end to back-end As a back-end beginner who transforms from front-end development, you already have the foundation of nodejs,...

How to use predefined time zone with Golang? How to use predefined time zone with Golang? Jun 06, 2024 pm 01:02 PM

Using predefined time zones in Go includes the following steps: Import the "time" package. Load a specific time zone through the LoadLocation function. Use the loaded time zone in operations such as creating Time objects, parsing time strings, and performing date and time conversions. Compare dates using different time zones to illustrate the application of the predefined time zone feature.

Golang framework development practical tutorial: FAQs Golang framework development practical tutorial: FAQs Jun 06, 2024 am 11:02 AM

Go framework development FAQ: Framework selection: Depends on application requirements and developer preferences, such as Gin (API), Echo (extensible), Beego (ORM), Iris (performance). Installation and use: Use the gomod command to install, import the framework and use it. Database interaction: Use ORM libraries, such as gorm, to establish database connections and operations. Authentication and authorization: Use session management and authentication middleware such as gin-contrib/sessions. Practical case: Use the Gin framework to build a simple blog API that provides POST, GET and other functions.

See all articles