如何利用Kotlin契约实现中缀函数的类型断言?
问题根源与解决办法
你的中缀函数契约失效的核心问题是泛型参数的定义逻辑完全搞反了:
你原本的泛型TYPE : Class<out Any>,意味着TYPE代表的是Class类型本身(比如String::class.java这个对象的类型),而不是我们要检查的目标实例类型(比如String)。契约里写this@isType is TYPE,实际是告诉编译器“当函数返回true时,这个变量是一个Class对象”——这显然和你想要的“变量是String实例”的推断完全无关。
修正后的实现
调整泛型参数,让TYPE代表我们要检查的目标实例类型,而参数接收该类型的Class对象:
@OptIn(ExperimentalContracts::class) inline infix fun <SELF, reified TYPE> SELF.isType(type: Class<TYPE>): Boolean { contract { returns(true) implies (this@isType is TYPE) } return type.isInstance(this) } fun demo() { val someValue: Any = if (System.currentTimeMillis() <= 1) 12345 else "some-string" val someType = String::class.java // 现在if块内无需强转,编译器能自动推断someValue是String类型 if (someValue isType someType) { println("length is " + someValue.length) } }
更简洁的KClass版本
如果用Kotlin原生的KClass,写法会更贴合Kotlin风格,无需依赖Java的Class:
@OptIn(ExperimentalContracts::class) inline infix fun <SELF, reified TYPE> SELF.isType(type: KClass<TYPE>): Boolean { contract { returns(true) implies (this@isType is TYPE) } return type.isInstance(this) } // 调用时直接用KClass引用 if (someValue isType String::class) { println("length is " + someValue.length) }
关键逻辑说明
- 泛型
reified TYPE现在指向的是我们要检查的实例类型(比如String),而非Class对象的类型。 - 契约中的
this@isType is TYPE准确表达了“当函数返回true时,变量是TYPE类型的实例”,编译器能正确识别这个推断规则。 - 函数内部的
type.isInstance(this)依然能正确完成类型检查,因为type是对应TYPE的Class/KClass对象。
内容的提问来源于stack exchange,提问作者java.is.for.desktop
相关产品推荐
相关产品推荐

