使用Kotlin契约在Iterable函数谓词中强制转换类型 [英] Using Kotlin contracts to cast type inside Iterable function predicate
问题描述
我有这个密封的类PictureEvent
:
sealed class PictureEvent {
data class PictureCreated(val pictureId: String, val url: String) : PictureEvent()
//more classes extending PictureEvent
}
现在,从PictureEvent
列表中,我想获得第一个PictureCreated
:
Now, from a list of PictureEvent
s, I want to get the first PictureCreated
:
fun doSomething(events: List<PictureEvent>) {
val creationEvent = events.first { isCreationEvent(it) } as PictureEvent.PictureCreated
//do stuff with the creationEvent
}
private fun isCreationEvent(event: PictureEvent) : Boolean {
return event is PictureEvent.PictureCreated
}
工作正常.如您所见,由于first
方法返回PictureEvent
,所以我将事件强制转换为PictureCreated
(使用as
关键字).我想知道是否可以通过使用Kotlin合同来避免这种转换.
It works fine. As you see, I'm casting the event to PictureCreated
(using as
keyword), since first
method, returns a PictureEvent
. I wonder if it's possible to avoid this casting by using Kotlin contracts.
我已经尝试过了:
private fun isCreationEvent(event: PictureEvent) : Boolean {
contract {
returns(true) implies (event is PictureEvent.PictureCreated)
}
return event is PictureEvent.PictureCreated
}
但是它不起作用; first
方法继续返回PictureEvent
,而不是PictureCreated
.目前可以这样做吗?
But it doesn't work; first
method keep returning a PictureEvent
, instead of PictureCreated
. Is it possible to do this currently?
推荐答案
合同很好,但是,如果您查看first
方法签名,您应该能够了解正在发生的事情以及找到的对象的原因不是自动广播:
The contract works fine, however if you take a look at the first
method signature, you should be able to understand what is happening and why the found object isn't autocast:
public inline fun <T> Iterable<T>.first(predicate: (T) -> Boolean): T
first
方法的返回类型与为Iterable
实例中的所有元素定义的返回类型相同,在您的情况下为PictureEvent
,并且不幸的是,谓词内部没有自动广播可以更改此类型.
The return type of the first
method is just the same as that defined for all elements in the Iterable
instance, PictureEvent
in your case, and no autocasting inside the predicate can unfortunately change that.
例如,可以使用所需的类类型来过滤列表,而不是使用合同,然后使用第一个元素:
Instead of contracts, for example, you can filter your list by the desired class type first, and then take the first element:
val creationEvent = events
.filterIsInstance(PictureEvent.PictureCreated::class.java)
.first()
或创建类似于first
的自己的扩展名:
or create your own extension similar to first
:
inline fun <reified R> Iterable<*>.firstOfInstance(): R {
val first = first { it is R }
return first as R
}
// or wrapping filterIsInstance
inline fun <reified R> Iterable<*>.firstOfInstance(): R {
return filterIsInstance(R::class.java).first()
}
val creationEvent = events.firstOfInstance<PictureEvent.PictureCreated>()
这篇关于使用Kotlin契约在Iterable函数谓词中强制转换类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!