Kotlin – 反射和类型安全

huangapple go评论62阅读模式
英文:

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 &quot;foo&quot;,
    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&lt;BASE, FIELD&gt;

infix fun &lt;BASE: Any, FIELD: Any&gt; KProperty1&lt;BASE, FIELD&gt;.equal(value: FIELD): KpaFilter&lt;BASE, FIELD&gt; { ... }

fun &lt;BASE: Any&gt; where(vararg filters: KpaFilter&lt;BASE, *&gt;?): KpaQuery&lt;BASE&gt;

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(&quot;INVISIBLE_REFERENCE&quot;, &quot;INVISIBLE_MEMBER&quot;)
infix fun &lt;BASE: Any, FIELD: Any&gt; KProperty1&lt;BASE, @kotlin.internal.Exact FIELD&gt;.equal(value: FIELD): KpaFilter&lt;BASE, FIELD&gt; { ... }

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.

huangapple
  • 本文由 发表于 2023年2月10日 07:07:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75405386.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定