第12章 反射

Go语言提供了一种机制,在编译时不知道类型的情况下,可更新变量、在运行时查看值、调用方法以及直接对它们的布局进行操作,这种机制称为反射(reflection)。反射也让我们可以把类型当作头等值。
本章将探讨Go语言的反射能力以及它如何增强语言的表达能力,特别是他在实现两个重要API中的关键作用。这两个API分别是fmt包提供的字符串格式化功能,以及encoding/json和encoding/xml这种包提供的协议编码功能。反射在text/tmplate和html/template包提供的模版机制中也很重要。另外,反射的推导比较复杂,也不是为了随意使用而设计的,因此尽管这些包使用反射来实现,但它们并没有在自己的API中暴露反射。

12.1 为什么使用反射

有时我们需要写一个函数有能力统一处理各种值类型的函数,而这些类型可能无法共享同一个接口,也可能布局未知,也可能这个类型在我们设计时还不存在,甚至这个类型会同时存在上面三种问题。
一个熟悉的例子是fmt.Printf中的格式化逻辑,他可以输出任意类型的任意值,甚至是用户自定义的一个类型。让我们先尝试用我们已学到的知识来实现一个类似的函数。为了简化起见,该函数只接受一个参数,并且与fmt.Sprint一样返回一个字符串,所以我们称这个函数为Sprint。
我们先用类型分支来判断这个参数是否定义了一个String方法,如果已定义则直接调用它。然后添加一些switch分支来判断参数的动态类型是否是基本类型(如string、int、bool等),再对每种类型采用不同的格式化操作。

1
func Sprint