Kotlin反射与类型安全:SQL查询生成库的类型安全API实现
如何在Kotlin的SQL查询DSL中实现类型安全的过滤条件?
我正在编写一个用于程序化生成SQL查询的小型库,期望其API可以按如下方式使用:
myQuery.where( MyClass::id equal "foo", MyClass::age notEqual 55 ).findAll()
目前我已定义了相关的接口与函数:
interface KpaFilter<BASE, FIELD> infix fun <BASE: Any, FIELD: Any> KProperty1<BASE, FIELD>.equal(value: FIELD): KpaFilter<BASE, FIELD> { ... } fun <BASE: Any> where(vararg filters: KpaFilter<BASE, *>?): KpaQuery<BASE>
但仍无法实现类型安全,例如以下代码本应触发编译错误,却能正常编译:
val someFilter = MyClass::id equal 55 // id 是 String 类型
请问是否可以通过修改上述声明的签名,在不使API变得繁琐的前提下实现此类类型安全?
解决方案
问题的核心在于KProperty1的第二个类型参数是协变的(out V),这使得编译器可以将KProperty1<MyClass, String>向上转型为KProperty1<MyClass, Any>,进而让equal函数的泛型参数FIELD被推断为Any,从而接受不匹配的类型(比如Int)作为参数。
要在保持API简洁的前提下实现编译期类型安全,只需将equal(以及notEqual等同类函数)修改为inline函数并使用reified泛型——这会让编译器在编译期保留精确的类型信息,直接阻止类型不匹配的调用:
interface KpaFilter<BASE, FIELD> // 改造equal函数:添加inline和reified泛型 inline infix fun <BASE: Any, reified FIELD: Any> KProperty1<BASE, FIELD>.equal(value: FIELD): KpaFilter<BASE, FIELD> { // 你的过滤逻辑实现 } // notEqual函数同理改造 inline infix fun <BASE: Any, reified FIELD: Any> KProperty1<BASE, FIELD>.notEqual(value: FIELD): KpaFilter<BASE, FIELD> { // 你的过滤逻辑实现 } fun <BASE: Any> where(vararg filters: KpaFilter<BASE, *>?): KpaQuery<BASE> { ... }
改造后,当你尝试执行MyClass::id equal 55时,编译器会明确识别出属性id的类型是String,而55是Int类型,直接触发编译错误,完全符合类型安全要求。同时API的调用方式和之前完全一致,不会增加使用负担。
内容的提问来源于stack exchange,提问作者Alkis Mavridis
相关产品推荐
相关产品推荐

