Go系列教程之反射的用法

论坛 期权论坛 脚本     
niminba   2021-5-23 03:00   847   0

反射是 Go 语言的高级主题之一。我会尽可能让它变得简单易懂。

本教程分为如下小节。

  • 什么是反射?
  • 为何需要检查变量,确定变量的类型?
  • reflect 包
    • reflect.Type 和 reflect.Value
    • reflect.Kind
    • NumField() 和 Field() 方法
    • Int() 和 String() 方法
  • 完整的程序
  • 我们应该使用反射吗?

让我们来逐个讨论这些章节。

什么是反射?

反射就是程序能够在运行时检查变量和值,求出它们的类型。你可能还不太懂,这没关系。在本教程结束后,你就会清楚地理解反射,所以跟着我们的教程学习吧。

为何需要检查变量,确定变量的类型?

在学习反射时,所有人首先面临的疑惑就是:如果程序中每个变量都是我们自己定义的,那么在编译时就可以知道变量类型了,为什么我们还需要在运行时检查变量,求出它的类型呢?没错,在大多数时候都是这样,但并非总是如此。

我来解释一下吧。下面我们编写一个简单的程序。

package main

import (
 "fmt"
)

func main() {
 i := 10
 fmt.Printf("%d %T", i, i)
}

在 playground 上运行

在上面的程序中,i 的类型在编译时就知道了,然后我们在下一行打印出 i。这里没什么特别之处。

现在了解一下,需要在运行时求得变量类型的情况。假如我们要编写一个简单的函数,它接收结构体作为参数,并用它来创建一个 SQL 插入查询。

考虑下面的程序:

package main

import (
 "fmt"
)

type order struct {
 ordId  int
 customerId int
}

func main() {
 o := order{
  ordId:  1234,
  customerId: 567,
 }
 fmt.Println(o)
}

在 playground 上运行

在上面的程序中,我们需要编写一个函数,接收结构体变量 o 作为参数,返回下面的 SQL 插入查询。

insert into order values(1234, 567)

这个函数写起来很简单。我们现在编写这个函数。

package main

import (
 "fmt"
)

type order struct {
 ordId  int
 customerId int
}

func createQuery(o order) string {
 i := fmt.Sprintf("insert into order values(%d, %d)", o.ordId, o.customerId)
 return i
}

func main() {
 o := order{
  ordId:  1234,
  customerId: 567,
 }
 fmt.Println(createQuery(o))
}

在 playground 上运行

在第 12 行,createQuery 函数用 o 的两个字段(ordId 和 customerId),创建了插入查询。该程序会输出:

insert into order values(1234, 567)

现在我们来升级这个查询生成器。如果我们想让它变得通用,可以适用于任何结构体类型,该怎么办呢?我们用程序来理解一下。

package main

type order struct {
 ordId  int
 customerId int
}

type employee struct {
 name string
 id int
 address string
 salary int
 country string
}

func createQuery(q interface{}) string {
}

func main() {

}

我们的目标就是完成 createQuery 函数(上述程序中的第 16 行),它可以接收任何结构体作为参数,根据结构体的字段创建插入查询。

例如,如果我们传入下面的结构体:

o := order {
 ordId: 1234,
 customerId: 567
}

createQuery 函数应该返回:

insert into order values (1234, 567)

类似地,如果我们传入:

 e := employee {
  name: "Naveen",
  id: 565,
  address: "Science Park Road, Singapore",
  salary: 90000,
  country: "Singapore",
 }

该函数会返回:

insert into employee values("Naveen", 565, "Science Park Road, Singapore", 90000, "Singapore")

由于 createQuery 函数应该适用于任何结构体,因此它接收 interface{} 作为参数。为了简单起见,我们只处理包含 string 和 int 类型字段的结构体,但可以扩展为包含任何类型的字段。

createQuery 函数应该适用于所有的结构体。因此,要编写这个函数,就必须在运行时检查传递过来的结构体参数的类型,找到结构体字段,接着创建查询。这时就需要用到反射了。在本教程的下一步,我们将会学习如何使用 reflect 包来实现它。

reflect 包

在 Go 语言中,reflect 实现了迓ТVW'f&"W2VB"VW'bV

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1060120
帖子:212021
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP