调用泛型函数时如何提示编译器推导返回类型
优化Kotlin泛型函数callPy2的类型推导体验
先看你实现的跨进程调用Python的泛型函数:
inline fun<reified Tin0, reified Tin1, reified Tout> callPy2( methodName: String, input0: Tin0, input1: Tin1 ): Tout { // 示例逻辑:实际应为跨进程JSON调用逻辑 return Json.decodeFromString<Tout>("123") }
当显式指定变量接收类型时,编译器能正确推导返回类型Tout:
val resultA: Float = callPy2("test", 30, 0.5) assertEquals(123f, resultA) val resultB: Int = callPy2("test", 30, 0.5) assertEquals(123, resultB)
但存在几个不友好的场景:
- 未指定接收类型时,编译器无法推导
Tout:// 报错:Cannot infer type for type parameter 'Tout'. Specify it explicitly. val result = callPy2("multi", 3, 4) - 在表达式中直接使用时,无法省略泛型参数:
// 报错:无法推导Tout类型 val result: Int = 1000 + callPy2("multi", 3, 4) - 无法仅指定
Tout,必须全量声明所有泛型参数(即使输入类型编译器已知):// 语法错误,无法仅指定单个泛型参数 val result = callPy2<Int>("multi", 3, 4) // 必须重复声明已知的输入类型,繁琐 val resultC = 10000 + callPy2<Int, Float, Float>("test", 3, 4f)
最优解决方案:调整泛型参数顺序
Kotlin的泛型参数推导是按顺序进行的,将需要显式指定的Tout放在泛型参数列表的最前面,输入类型参数Tin0、Tin1后置,编译器就能自动推导输入类型,同时允许你仅显式指定返回类型:
修改后的函数:
inline fun<reified Tout, reified Tin0, reified Tin1> callPy2( methodName: String, input0: Tin0, input1: Tin1 ): Tout { // 保留原有业务逻辑 return Json.decodeFromString<Tout>("123") }
现在所有场景都能优雅处理:
- 直接指定返回类型,输入类型自动推导:
val result = callPy2<Int>("multi", 3, 4) // 正常编译,Tin0/Tin1自动识别为Int - 在表达式中直接使用:
val result: Int = 1000 + callPy2<Int>("multi", 3, 4) // 正常运行 - 原有指定接收类型的方式依然有效:
val resultA: Float = callPy2("test", 30, 0.5) // 编译器自动推导Tout=Float - 特殊场景下仍可全量指定泛型参数(比如输入类型存在歧义时):
val resultC = 10000 + callPy2<Float, Int, Float>("test", 3, 4f) assertEquals(10123f, resultC)
补充方案:重载简化版函数
如果不想修改原函数的泛型顺序,可以重载一个仅接收返回类型泛型的版本,内部调用原函数:
// 简化调用的重载版本,仅指定Tout,输入类型自动推导 inline fun<reified Tout> callPy2( methodName: String, input0: Any, input1: Any ): Tout { return callPy2<Any, Any, Tout>(methodName, input0, input1) }
但这种方案会丢失输入类型的编译时检查,不如调整泛型顺序的方案优雅,因此优先推荐第一种方案。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

