用 reflect.typeof 获取函数类型信息时,必须传函数名或取地址(如 reflect.typeof(myfunc)),不可加括号调用;其 kind() 必须为 reflect.func,numin() 返回参数个数(不含 receiver),in(i) 获取第 i 个参数类型,变参视为切片。

用 reflect.TypeOf 获取函数类型信息
Go 的反射不能直接作用于函数值本身,必须先用 reflect.TypeOf 提取其类型(reflect.Type),再调用 NumIn() 和 In(i) 才能拿到参数个数与类型。传入函数时别忘了加括号取地址 —— 传 func() 值会 panic,必须传 &func 或直接传函数名(Go 里函数名本身就是值)。
常见错误:写成 reflect.TypeOf(myFunc()),这会先执行函数;正确写法是 reflect.TypeOf(myFunc)。
-
reflect.TypeOf(fn).Kind()必须是reflect.Func,否则后续方法不可用 - 如果函数是方法值(如
(obj.Method)),类型仍是Func,但接收者已绑定,参数列表不含隐式 receiver - 匿名函数、闭包同样适用,只要它是函数类型
NumIn() 和 In(i) 的行为边界
NumIn() 返回的是函数声明的参数个数,不包括 receiver(哪怕你传的是方法表达式)。它和 NumOut() 是对称的,但要注意:变参函数(...T)在这里被当作一个普通参数,NumIn() 返回值不会因是否变参而变化,只是 In(n-1) 的类型是 []T(切片),而非 T。
- 例如
func(int, string, ...interface{})→NumIn()返回3,最后一个In(2)类型是reflect.Slice - 参数索引从
0开始,In(i)越界会 panic,务必用i 判断 -
In(i)返回的是reflect.Type,要获取底层类型需调用.Name()(导出类型)或.String()(含包路径)
实际提取参数类型的典型写法
最简可靠模式就是先断言类型,再遍历。别依赖 reflect.ValueOf(fn).Type() —— ValueOf 对函数返回的是不可寻址的 Func 类型 Value,虽然也能调 Type(),但语义不如直接 reflect.TypeOf 清晰。
fn := func(a int, b string, c []byte) {}
t := reflect.TypeOf(fn)
if t.Kind() != reflect.Func {
panic("not a function")
}
fmt.Println("param count:", t.NumIn())
for i := 0; i
<p>注意:<code>paramType.Name()</code> 对内置类型(如 <code>int</code>、<code>string</code>)返回空字符串,此时得用 <code>paramType.String()</code> 才能看清真实类型名。</p>
<h3>反射获取参数类型时的性能与限制</h3>
<p>反射开销不小,且无法在编译期校验 —— 如果函数签名改了,反射代码不会报错,只会在运行时 panic。更麻烦的是:无法区分命名类型和底层类型相同的别名(比如 <code>type MyInt int</code> 和 <code>int</code> 在 <code>In(i).Kind()</code> 上都是 <code>reflect.Int</code>,需用 <code>.Name()</code> + <code>.PkgPath()</code> 组合判断是否为自定义类型。</p>
- 交叉编译或 vendoring 场景下,
PkgPath()可能为空(如标准库类型),需兼容处理 - 接口类型参数(如
io.Reader)返回的是接口的reflect.Interface,不是其实现类型 - 不支持获取参数名 —— Go 的函数类型信息里根本不存形参标识符,只有类型序列
真要靠参数名做逻辑,只能靠源码解析(go/ast)或注解工具,反射做不到。











