Kotlin Contracts:在具体化类型参数上断言实例
Kotlin Contracts: assert instance on reified type parameter
我正在尝试编写一个断言函数来检查给定对象是否属于 T
:
类型
@UseExperimental(ExperimentalContracts::class)
inline fun <reified T> assertIsInstance(value: Any?) {
contract {
returns() implies (value is T)
}
Assertions.assertThat(value).isInstanceOf(T::class.java)
}
该函数使用 AssertJ 进行具体断言,但我愿意让编译器知道在其执行后,value
是 T
类型,因此可以进行智能转换。这似乎不起作用,因为:
Error in contract description: references to type parameters are forbidden in contracts
还有其他方法可以实现这种行为吗?这里有什么问题?这最终会成为可能吗?
(使用 Kotlin v1.3)
在某些时候,IDE 对此类结构的支持存在一些(深层次的技术)担忧,但未来可能会放宽此限制。
这已经困扰我几个小时了,特别是因为这是可能的:
val x: Any = "string"
require(x is String)
val len = x.length
编译器显然能够理解这些,所以这很可能是合约本身的限制。
我已经花了一段时间尝试想出一些解决方法。供参考:
@UseExperimental(ExperimentalContracts::class)
inline fun <reified T> assertIsInstance(value: Any?) {
contract {
returns() implies T::class.isInstance(value))
}
if(value !is T){
throw java.lang.IllegalArgumentException("Incorrect type");
}
}
"Unsupported construct"
@UseExperimental(ExperimentalContracts::class)
inline fun <reified T> assertIsInstance(value: Any?, condition: Boolean = value is T) {
contract {
returns() implies condition
}
if(!condition)
throw IllegalArgumentException("Incorrect type");
}
编译,但不启用智能转换。其背后的最初动机是在合约前面放置一个布尔值,但合约需要成为函数的第一部分,这使得这成为不可能。您不妨删除合同;在这种情况下没用。
这是我最后一次尝试:
@UseExperimental(ExperimentalContracts::class)
inline fun assertIsInstance(value: Any?, cls: KClass<out Any>) {
contract {
returns() implies (cls.isInstance(value))
}
if(!cls.isInstance(value))
throw IllegalArgumentException("");
}
另一个"unsupported construct"。
不知何故我得到了这个:
@UseExperimental(ExperimentalContracts::class)
inline fun assertIsInstance(value: Any?) {
contract {
returns() implies (value.hashCode() == 0)
}
if(value.hashCode() != 0)
throw java.lang.IllegalArgumentException();
}
但这给出了一个新的错误:only references to parameters are allowed in contract description
。
长话短说:
看来你做不到。像我在第二个示例中所做的那样潜入它不会触发智能转换,其余的由于各种编译器错误而无法工作。
至少目前看来没有办法。您当然可以在 Kotlin 存储库中打开一个问题并请求这样的东西,但目前看来还不可能。
as 运算符不这样做吗?
fun main() {
val x: Any = "string"
x as String
val len = x.length
println(len)
}
我正在尝试编写一个断言函数来检查给定对象是否属于 T
:
@UseExperimental(ExperimentalContracts::class)
inline fun <reified T> assertIsInstance(value: Any?) {
contract {
returns() implies (value is T)
}
Assertions.assertThat(value).isInstanceOf(T::class.java)
}
该函数使用 AssertJ 进行具体断言,但我愿意让编译器知道在其执行后,value
是 T
类型,因此可以进行智能转换。这似乎不起作用,因为:
Error in contract description: references to type parameters are forbidden in contracts
还有其他方法可以实现这种行为吗?这里有什么问题?这最终会成为可能吗?
(使用 Kotlin v1.3)
在某些时候,IDE 对此类结构的支持存在一些(深层次的技术)担忧,但未来可能会放宽此限制。
这已经困扰我几个小时了,特别是因为这是可能的:
val x: Any = "string"
require(x is String)
val len = x.length
编译器显然能够理解这些,所以这很可能是合约本身的限制。
我已经花了一段时间尝试想出一些解决方法。供参考:
@UseExperimental(ExperimentalContracts::class)
inline fun <reified T> assertIsInstance(value: Any?) {
contract {
returns() implies T::class.isInstance(value))
}
if(value !is T){
throw java.lang.IllegalArgumentException("Incorrect type");
}
}
"Unsupported construct"
@UseExperimental(ExperimentalContracts::class)
inline fun <reified T> assertIsInstance(value: Any?, condition: Boolean = value is T) {
contract {
returns() implies condition
}
if(!condition)
throw IllegalArgumentException("Incorrect type");
}
编译,但不启用智能转换。其背后的最初动机是在合约前面放置一个布尔值,但合约需要成为函数的第一部分,这使得这成为不可能。您不妨删除合同;在这种情况下没用。
这是我最后一次尝试:
@UseExperimental(ExperimentalContracts::class)
inline fun assertIsInstance(value: Any?, cls: KClass<out Any>) {
contract {
returns() implies (cls.isInstance(value))
}
if(!cls.isInstance(value))
throw IllegalArgumentException("");
}
另一个"unsupported construct"。
不知何故我得到了这个:
@UseExperimental(ExperimentalContracts::class)
inline fun assertIsInstance(value: Any?) {
contract {
returns() implies (value.hashCode() == 0)
}
if(value.hashCode() != 0)
throw java.lang.IllegalArgumentException();
}
但这给出了一个新的错误:only references to parameters are allowed in contract description
。
长话短说:
看来你做不到。像我在第二个示例中所做的那样潜入它不会触发智能转换,其余的由于各种编译器错误而无法工作。
至少目前看来没有办法。您当然可以在 Kotlin 存储库中打开一个问题并请求这样的东西,但目前看来还不可能。
as 运算符不这样做吗?
fun main() {
val x: Any = "string"
x as String
val len = x.length
println(len)
}