安全的科特林流利铸造?

时间:2020-02-29 14:34:45

标签: generics kotlin casting fluent

具有以下扩展功能:

inline fun <reified OUT> Any.cast(): OUT = this as OUT
inline fun <reified IN, reified OUT: IN> IN.downcast(): OUT = this as OUT
inline fun <reified IN: OUT, reified OUT> IN.upcast(): OUT = this as OUT

我可以这样使用它们:

val x1: Number = 42
val x2: String = "abc"
val x3: Double = 3.14

val y1: Int = x1.downcast<Number, Int>()
val y2: CharSequence = x2.upcast<String, CharSequence>()
val y3: Float = x3.cast<Float>() // dangerous, crash

第一个问题是我必须写:

x1.downcast<Number, Int>()

代替

x1.downcast<Int>()

第二个问题是,即使我实现了x1.upcast<Int>()语法,IN通用参数也很容易推导出为Any,因此它将始终有效,这是不希望的。


以下示例显示了现实生活场景中的简化不良情况:

interface A1Able
class B1Impl : A1Able { val desiredField = 42 }
class C1Impl : A1Able

interface A2Able
class B2Impl : A2Able { val someField: A1Able = C1Impl() }
class C2Impl : A2Able { val someField: A1Able = B1Impl() }

interface A3Able
class B3Impl : A3Able { val someField: A2Able = C2Impl() }
class C3Impl : A3Able { val someField: A2Able = B2Impl() }

interface A4Able
class C4Impl : A4Able { val someField: A3Able = B3Impl() }

fun main() {
  val source: A4Able = C4Impl()
  val desiredField = ((((source as C4Impl).someField as B3Impl).someField as C2Impl).someField as B1Impl).desiredField
}

这就是我所说的括号地狱。使用语法,我尝试实现以下外观(不安全的强制转换版本):

source.cast<C4Impl>().someField.cast<B3Impl>().someField.cast<C2Impl>().someField.cast<B1Impl>().desiredField

它的语法不是较短的,可读性更强,并且没有括号地狱。问题是我无法通过这种方式进行类型检查,因此我可能会写"abc".cast<Int>()并导致异常。


如何使它更安全并保持流利的语法?

0 个答案:

没有答案