Kotlin中createPropertyReader函数的类型推断问题:类型不匹配未触发编译错误
嘿,我来帮你理清这个问题~
首先,咱们得搞清楚为什么Kotlin没给你报编译错:这其实是Kotlin类型推断的设计特性导致的。当你调用带多个泛型参数的函数时,Kotlin会尝试找到一个共同的最小上界类型(也就是能同时兼容两个参数类型的超类型)来作为泛型T的类型。
在你的例子里,User::id的类型是Uuid,而lambda返回的是String。Kotlin找到了它们的共同超类型——也就是同时实现了Serializable、Comparable这些接口的交集类型,所以把T推断成了那个奇怪的Comparable<...> & Serializable!类型,而不是直接报错。这是Kotlin为了增加类型灵活性做的设计,但刚好和你想要的严格类型安全需求冲突了。
那怎么才能实现你要的严格类型检查呢?给你两个实用的解决方案:
方案1:分阶段调用函数,先固定T的类型
最直接的办法是把函数改成高阶函数,先传入property来确定T的类型,再传入lambda。这样T会被property的类型完全锁定,lambda必须返回和property完全匹配的类型,否则直接报编译错。
重写后的函数和使用方式如下:
// 重写createPropertyReader,返回一个接收lambda的函数 fun <R, T> createPropertyReader(property: KProperty1<R, T>): ((R) -> T) -> PropertyReader<R, T> { return { readFunction -> PropertyReader(property, readFunction) } } // 使用时先传property,再传lambda val x = createPropertyReader(User::id) { user -> // 这里如果返回String,编译器会直接报错:Type mismatch: inferred type is String but Uuid was expected readString() }
方案2:添加编译期类型检查(利用reified T)
如果不想改变函数的调用方式,你可以借助reified T和Kotlin的typeOf函数(需要开启ExperimentalStdlibApi)来添加一个编译期的类型校验。虽然这个校验写法上是运行时判断,但因为内联函数和reified的特性,Kotlin会在编译期就发现类型不匹配并报错。
代码示例:
@OptIn(ExperimentalStdlibApi::class) inline fun <R, reified T> createPropertyReader( property: KProperty1<R, T>, noinline readFunction: (R) -> T ): PropertyReader<R, T> { // 校验lambda返回类型和property的类型完全一致 if (property.returnType != typeOf<T>()) { error("类型不匹配:属性类型是${property.returnType},但函数返回类型是${typeOf<T>()}") } return PropertyReader(property, readFunction) }
总结
你遇到的问题本质是Kotlin类型推断的灵活性和你需要的严格类型安全之间的冲突。分阶段调用的方案最简洁可靠,能完全满足你要的编译期类型安全;如果不想改调用方式,用reified T加类型检查也能达到目的。
内容来源于stack exchange

