英文:
Kotlin - reflection and type safety
问题
我正在编写一个用于以编程方式生成SQL查询的小型库。目标是使该库的API可以像这样使用:
myQuery.where(
MyClass::id equal "foo",
MyClass::age notEqual 55
).findAll()
where
函数和中缀操作符的签名都在我的控制之下。以下是我目前拥有的相关定义:
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 是一个字符串
是否有可能以某种方式修改上述声明的签名,以实现这种类型安全,而不使API比其当前形式更繁琐?
英文:
I am writing a small library for programatically generating SQL queries.
The goal is that the API of this library can be used like that:
myQuery.where(
MyClass::id equal "foo",
MyClass::age notEqual 55
).findAll()
The signatures of both the where
function, and the infix operators is under my control. Here are the relevant definitions that I have at the moment:
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>
Still, I cannot find a proper way to make this type safe. For example, I would like this to raise a compilation error, but unfortunately, it compiles:
val someFilter = MyClass::id equal 55 // id is a string
Is it possible to somehow modify the signatures of the declarations above and achieve this kind of type safety, without making the API more cumbersome than its current form?
答案1
得分: 1
如果您不介意使用Kotlin内部API,编译器中有一个隐藏功能可以实现这一点。通过使用@kotlin.internal.Exact
注解参数来启用此功能:
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
infix fun <BASE: Any, FIELD: Any> KProperty1<BASE, @kotlin.internal.Exact FIELD>.equal(value: FIELD): KpaFilter<BASE, FIELD> { ... }
这在普通的Kotlin项目中非常有效,当然,我们不能保证它将来会得到支持。
英文:
If you don't mind using Kotlin internal APIs, there is a hidden feature in the compiler which does exactly this. The feature is enabled by annotating a parameter with @kotlin.internal.Exact
:
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
infix fun <BASE: Any, FIELD: Any> KProperty1<BASE, @kotlin.internal.Exact FIELD>.equal(value: FIELD): KpaFilter<BASE, FIELD> { ... }
This works pretty well and can be used in regular Kotlin projects. Of course, we don't have guarantees it will be supported in the future.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论