如何为Kotlin泛型函数的函数入参的参数和返回值添加泛型约束?
问题根因
约束失效本质是Kotlin泛型的逆变特性 + 无锚点泛型参数的类型推断规则共同导致的:
- 函数类型
(P) -> R的参数类型P是逆变点,只要A是B的子类型,(B) -> R就是(A) -> R的子类型 - 你定义的泛型参数
T没有直接出现在函数参数、返回值的声明中,只出现在V的类型约束里,编译器为了匹配你传入的函数类型,会自动把T推断为Nothing(Kotlin中所有类型的子类型,天然满足T: Base的约束),此时任何(*)->Unit类型的函数都符合(Nothing) -> Unit的父类型要求,自然绕过了约束。
正确实现方案
不需要拆分T和V两个泛型参数,直接把函数参数的类型明确声明为入参是Base子类、返回值为Unit即可,让泛型T直接锚定到函数参数的声明上:
interface Base // 直接把泛型约束写在T上,函数参数明确为(T) -> Unit fun <T : Base> exampleGenericFunction(func: (T) -> Unit) { println("func is $func") } class ImplementsBase : Base class DoesNotImplementBase fun main() { val f1: (ImplementsBase) -> Unit = { } exampleGenericFunction(f1) // 编译通过 val f2: (DoesNotImplementBase) -> Unit = { } exampleGenericFunction(f2) // 编译报错:DoesNotImplementBase 不符合上界 Base 的要求 }
如果确实需要保留单独的V泛型参数(比如需要对函数类型做更复杂的约束扩展),可以给T加一个锚点参数避免被推断为Nothing,例如可以加一个无实际作用的默认参数:
fun <T : Base, V : (T) -> Unit> exampleGenericFunction(func: V, @Suppress("UNUSED_PARAMETER") anchor: T? = null) { println("func is $func") }
这种写法同样能实现约束效果,调用时不需要主动传anchor参数。
内容的提问来源于stack exchange,提问作者David Hadley
相关产品推荐
相关产品推荐

