You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 07:25:40