使用 Kotlin 契约在 Iterable 函数谓词中转换类型
Using Kotlin contracts to cast type inside Iterable function predicate
这个我封了classPictureEvent
:
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
方法,returns 和 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
方法的 return 类型与为 Iterable
实例中的所有元素定义的类型相同,在您的情况下为 PictureEvent
,并且没有不幸的是,谓词内部的自动转换可能会改变这一点。
例如,您可以先按所需 class 类型过滤列表,然后取第一个元素:
,而不是合同
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>()
这个我封了classPictureEvent
:
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
方法,returns 和 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
方法的 return 类型与为 Iterable
实例中的所有元素定义的类型相同,在您的情况下为 PictureEvent
,并且没有不幸的是,谓词内部的自动转换可能会改变这一点。
例如,您可以先按所需 class 类型过滤列表,然后取第一个元素:
,而不是合同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>()