简单来说,我想要一个像这样的函数:
fun <T> convert(val foo: String, fooT: KType) : T {
...?
}
对于Int
,它将返回foo.toInt()
,对于Double
,,foo.toDouble()
并且返回某种未知类型,只需抛出一个异常。我认为为自己期望的类型创建自己的switch语句不是那么困难,但是出于好奇,已经有办法了吗?
不幸的是,没有简单的通用方法,因为我们不是在处理类型转换,而是在处理方法调用。这是我的方法:
fun <T> convert(str: String, type: KType) : T {
val result: Any = when (type.jvmErasure)
{
Long::class -> str.toLong()
Int::class -> str.toInt()
Short::class -> str.toShort()
Byte::class -> str.toByte()
...
else -> throw IllegalArgumentException("'$str' cannot be converted to $type")
}
return result as T // unchecked cast, but we know better than compiler
}
用法:
@UseExperimental(ExperimentalStdlibApi::class)
fun main() {
val int = convert<Int>("32", typeOf<Int>())
println("converted: $int")
}
除了KType
参数以外,您还可以使用aClass<T>
并使函数功能化,因此可以将其称为asconvert<Int>("32")
或even "32".toGeneric<Int>()
。
虽然没有简单的方式,是可以访问使用重型反射和依靠实现细节的类型。为此,我们可以从KType
对象中提取类型名称,找到匹配的扩展方法(在其他类中),然后使用反射对其进行调用。
我们必须使用to*OrNull()
代替to*()
,因为后者是内联的,不会通过反射找到。另外,我们需要求助于Java反射-此时,Kotlin反射会抛出UnsupportedOperationException
所涉及的类型。
我不建议在生产性代码中使用此方法,因为它效率低下并且可能会与将来的标准库版本一起使用,但这是一个不错的实验:
fun convert(str: String, type: KType): Any {
val conversionClass = Class.forName("kotlin.text.StringsKt")
// here, the to*OrNull() methods are stored
// we effectively look for static method StringsKt.to*OrNull(String)
val typeName = type.jvmErasure.simpleName
val funcName = "to${typeName}OrNull" // those are not inline
val func = try {
conversionClass.getMethod(funcName, String::class.java) // Java lookup
} catch (e: NoSuchMethodException) {
throw IllegalArgumentException("Type $type is not a valid string conversion target")
}
func.isAccessible = true // make sure we can call it
return func.invoke(null, str) // call it (null -> static method)
?: throw IllegalArgumentException("'$str' cannot be parsed to type $type")
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句