需先用 reflect.ValueOf 获取具体实现值(如 struct 实例),再 MethodByName 定位导出方法,最后以 []reflect.Value 参数调用 Call;接口变量须转具体类型后反射,不可直接对 interface 类型 Call。
Go 语言中接口变量本身不保存方法实现,只存动态类型和值;要动态调用其方法,必须先用 reflect.ValueOf 获取底层值,再通过 MethodByName 或 Method 定位方法,最后用 Call 执行。直接对接口变量的 reflect.Value 调用 Call 会 panic:「call of reflect.Value.Call on zero Value」。
reflect.Value.Elem() 解引用指针MethodByName 返回空 reflect.Value
[]reflect.Value,每个元素用 reflect.ValueOf(arg) 转换type Greeter interface {
SayHello(name string) string
}
type EnglishGreeter struct{}
func (e EnglishGreeter) SayHello(name string) string {
return "Hello,
" + name
}
g := EnglishGreeter{}
v := reflect.ValueOf(g) // 注意:不是 reflect.ValueOf(&g) 或 reflect.ValueOf((Greeter)(g))
method := v.MethodByName("SayHello")
if !method.IsValid() {
panic("method not found")
}
result := method.Call([]reflect.Value{reflect.ValueOf("Alice")})
fmt.Println(result[0].String()) // "Hello, Alice"
当变量声明为接口类型(如 var g Greeter = EnglishGreeter{}),reflect.ValueOf(g) 得到的是接口的反射值,其 Kind() 是 interface,不能直接调用 MethodByName —— 因为它内部封装了实际值,但未自动解包。
reflect.ValueOf(g).Elem() 会 panic:「can't call Elem on interface」reflect.ValueOf(g).Convert(reflect.TypeOf(EnglishGreeter{})).Interface() 强转(不推荐)reflect.ValueOf(g).Interface().(*EnglishGreeter) 类型断言后重新反射reflect.ValueOf(g).Type() 和 reflect.ValueOf(g).Interface() 获取底层类型与值,再反射操作反射调用时参数类型必须严格匹配签名,Go 不做隐式转换。常见错误包括:int 传成 int64、string 传成 *string、结构体字段未导出导致无法反射访问等。
reflect.ValueOf(x).Convert(targetType) 显式转换(仅限可转换类型,如 int ↔ int64)method.Type().In(i) 可获取第 i 个参数期望类型FieldByName 返回零值func (e *EnglishGreeter) SayHello(...)),必须传入指针的 reflect.Value,即 reflect.ValueOf(&g)
reflect.Value.Call 开销显著高于直接调用:涉及类型检查、栈帧构造、参数拷贝、GC 扫描等。基准测试显示,反射调用比直接调用慢 10–100 倍,且无法内联、逃逸分析受限。
reflect.Value.UnsafeAddr() + 函数指针绕过反射(极不推荐,破坏类型安全)go:generate + golang.org/x/tools/go/packages)替代运行时反射if g, ok := iface.(Greeter); ok { g.SayHello(...) }
真正难的不是调通,而是判断该不该用反射——多数时候,你其实只需要一个 map[string]func() 或 interface{} 类型的注册表,而不是硬上 reflect.Value.Call。