# 39 反射(Reflection)

Go是一门静态类型语言，绝大多数情况下，变量的类型在编译时就是已知的。

一种例外是接口类型，尤其是空接口`interface{}`。

空接口是一个动态类型，跟Java或C#里的`Object`类似。

在编译时，我们无法分辨接口类型的底层值是一个`int`还是`string`。

标准库中的[Reflect](https://golang.org/pkg/reflect/)包使得我们能够在运行时处理这些动态值。我们可以：

* 检查动态值的类型
* 枚举`struct`的字段
* 为字段设置值
* 在运行时创建一个新值

用于在运行时检查接口值的类型的相关语言级功能是[类型转换](https://denglj.gitbook.io/essential-go/12-empty-interface#lei-xing-jiao-huan-ji-type-switch)和[类型断言](https://denglj.gitbook.io/essential-go/12-empty-interface#lei-xing-duan-yan-type-assertion)。

```go
package main

import (
	"fmt"
	"reflect"
)

func main() {
	var v interface{} = 4
	var reflectVal reflect.Value = reflect.ValueOf(v)

	var typ reflect.Type = reflectVal.Type()
	fmt.Printf("Type '%s' of size: %d bytes\n", typ.Name(), typ.Size())
	if typ.Kind() == reflect.Int {
		fmt.Printf("v contains value of type int\n")
	}
}

// -----OUTPUT-------
// Type 'int' of size: 8 bytes
// v contains value of type int
```

上述代码是反射的基本操作：

* 从一个空接口(`interface{}`)类型的值开始
* 使用`reflect.ValueOf(v interface{})`去得到`reflect.Value`类型的变量，它表示关于该值的信息
* 使用`reflect.Value`去检查值的类型、值是否为`nil`、设置新的值

反射有[几个实际用途](https://denglj.gitbook.io/essential-go/common-standard-libraries/39-reflection/uses-for-reflection)。
