Go 没有 C++ 中的多态、模板相关的概念,类似的需求都是通过 interface 实现。
当实现类似 C++ 多态时,interface 更接近于 Python 中的 duck type:
type I interface {
Print()
}
type S struct {
}
func (s S) Print() {
// ...
}
func useI(i I) {
i.Print()
}
var s S = S{}
useI(s)
当实现类似 C++ 模板(更具体点应该是函数模板)时,interface 类似于 Java 中的 Object:
var v interface{}
v = 1
fmt.Println(v.(int))
如果跟 Go 自身比较,interface 类型实际上与 map、slice、chan 引用类型类似,变量自身只是一个简单的结构体,内部通过指针指向具体的存储区域。
Go 是静态类型的语言,在编译期间类型都已经确定,reflect 包存在的目的在于动态获取 interface 类型变量内部指针所指向的信息。具体而言,使用 reflect.Type 表示实际存储的数值的类型信息,使用 reflect.Value 表示实际存储的数值,相应的获取这两个信息的方法为 reflect.TypeOf(interface{}) 和 reflect.ValueOf(interface{})。
fmt.Println(reflect.TypeOf(1))
fmt.Println(reflect.ValueOf(1))
// Output:
int
1
reflect.Type 是一个 interface 类型,reflect.Value 是一个 struct 类型,对外的接口为各自的方法集以及 reflect 包中定义的一些辅助函数,其中 reflect.Value 可以通过自身的 func (Value) Type 方法返回对应的 reflect.Type 信息。
reflect.Type 和 reflec.Value 定义了一些同名的方法:
Elem, Field, FieldByIndex, FieldByName, FieldByNameFunc, Kind, Len, Method, MethodByName, NumField, NumMethod, String
需要注意的是,虽然两者定义的某些方法同名,但是方法的实现不相同,如:
Elem, Field, FieldByIndex, FieldByName, FieldByNameFunc, Method, MethodByName, String
注意 reflect.Type 与 reflect.Kind 的差异,reflect.Type.Kind() 或 reflect.Value.Kind() 返回的是一个 uint 枚举类型 reflect.Kind,其枚举值定义如下:
const (
Invalid Kind = iota
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Ptr
Slice
String
Struct
UnsafePointer
)
该枚举类型定义了 func (Kind) String 方法,因此在 printf 打印时会输出 Kind 枚举值所对应的字符串表示:
type S struct {
}
type I int
func main() {
a := 1
s := S{}
i := I(1)
m := map[string]int{}
fmt.Println("--- primitive:")
fmt.Println(reflect.TypeOf(a))
fmt.Println(reflect.TypeOf(a).Kind())
fmt.Println(reflect.ValueOf(a))
fmt.Println(reflect.ValueOf(a).Kind())
fmt.Println("--- struct:")
fmt.Println(reflect.TypeOf(s))
fmt.Println(reflect.TypeOf(s).Kind())
fmt.Println(reflect.ValueOf(s))
fmt.Println(reflect.ValueOf(s).Kind())
fmt.Println("--- typedef:")
fmt.Println(reflect.TypeOf(i))
fmt.Println(reflect.TypeOf(i).Kind())
fmt.Println(reflect.ValueOf(i))
fmt.Println(reflect.ValueOf(i).Kind())
fmt.Println("--- map:")
fmt.Println(reflect.TypeOf(m))
fmt.Println(reflect.TypeOf(m).Kind())
fmt.Println(reflect.ValueOf(m))
fmt.Println(reflect.ValueOf(m).Kind())
// Output:
--- primitive:
int
int
1
int
--- struct:
main.S
struct
{}
struct
--- typedef:
main.I
int
1
int
--- map:
map[string]int
map
map[]
map
此外,reflect.Value 还定义了一些类似 Float, Int, String, Uint 的方法用于返回底层实际存储的值。
更多关于 reflect 的信息可以参考 reflect 包的在线文档。
参考资料
Go Data Structures: Interfaces
https://research.swtch.com/interfaces
Part 34: Reflection
https://golangbot.com/reflection/
The Laws of Reflection
https://blog.golang.org/laws-of-reflection
Package reflect
https://golang.org/pkg/reflect/
最后修改于 2019-03-02