使用Kotlin契约在Iterable函数谓词中强制转换类型 [英] Using Kotlin contracts to cast type inside Iterable function predicate

查看:96
本文介绍了使用Kotlin契约在Iterable函数谓词中强制转换类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个密封的类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 PictureEvents, 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆