使用Kotlin契约在Iterable函数谓词内部强制转换类型



我有这个密封类PictureEvent:

sealed class PictureEvent {
data class PictureCreated(val pictureId: String, val url: String) : PictureEvent()
//more classes extending PictureEvent
}

现在,从PictureEvent的列表中,我想获得第一个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
}

它运行良好。如您所见,我将事件强制转换为PictureCreated(使用as关键字(,因为first方法返回一个PictureEvent。我想知道是否可以通过使用Kotlin合同来避免这种铸造。

我试过这个:

private fun isCreationEvent(event: PictureEvent) : Boolean {
contract {
returns(true) implies (event is PictureEvent.PictureCreated)
}
return event is PictureEvent.PictureCreated
}

但它不起作用;first方法保持返回PictureEvent,而不是PictureCreated。目前有可能这样做吗?

合约运行良好,但如果您查看first方法签名,您应该能够了解发生了什么,以及为什么找到的对象不是自动播放的:

public inline fun <T> Iterable<T>.first(predicate: (T) -> Boolean): T

first方法的返回类型与为Iterable实例中的所有元素定义的返回类型相同,在您的情况下为PictureEvent,不幸的是,谓词内部的自动转换无法改变这一点。


例如,您可以先根据所需的类类型过滤列表,然后使用第一个元素:

val creationEvent = events
.filterIsInstance(PictureEvent.PictureCreated::class.java)
.first()

或者创建类似于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>()

相关内容

  • 没有找到相关文章

最新更新