将字符串转换为Kotlin中的任何数据类型
我正在尝试创建一个通用函数,以将任何字符串转换为任何数据类型。 例如,
convert<Int>("23") => 23
convert<LocalDateTime>("2022-06-29T18:02:00") => LocalDateTime object
convert<String>("hg") => "hg"
如果不可能,请丢弃错误。
这是用于执行此操作的代码,而无需进行任何错误处理。
/**
* Convert a string to given class type or throw an error if it is not valid
*/
inline fun <reified T> stringToTypeOrError(value: String): T {
val v: T = when (T::class) {
Int::class -> value.toInt() as T
String::class -> value as T
Double::class -> value.toDouble() as T
LocalDateTime::class -> LocalDateTime.parse(value) as T
else -> throw BadRequestException("Does Not Support : $value.")
}
return v
}
但是,当我尝试将字符串转换为枚举时,我会遇到问题。 例如,如果我需要转换为枚举。
convert<Order>("asc") => Order.ASC
为了支持所有枚举,我尝试了以下操作:
enum class Order { ASC, DESC }
/**
* Convert a string to enum or throw a custom error
*/
inline fun <reified E : Enum<E>> enumValueOrError(value: String): E {
return try {
enumValueOf(value)
} catch (e: java.lang.IllegalArgumentException) {
throw BadRequestException("Does Not Support : $value.")
}
}
/**
* Convert a string to a given class type or throw an error if it is not valid
*/
inline fun <reified T> stringToTypeOrError(value: String): T {
// TODO: Handle all exceptions
val v: T = when (T::class) {
Int::class -> value.toInt() as T
String::class -> value as T
Double::class -> value.toDouble() as T
LocalDateTime::class -> LocalDateTime.parse(value) as T
else -> {
if (T::class.javaClass.isEnum) {
return enumValueOrError<T>(value)
} else {
throw NotImplementedError("Not implemented for type:${T::class.qualifiedName}")
}
}
}
return v
}
构建失败说:
Type argument is not within its bounds: should be subtype of 'Enum<TypeVariable(E)>'
在中返回EnumvalueorError&lt; t&gt;(value)
关于如何解决此问题的任何想法? 或如何通过enumvalueorError
函数传递通用类型t
(案例时,不在中添加每个枚举)
I am trying to create a generic function to convert any string to any data type.
For example
convert<Int>("23") => 23
convert<LocalDateTime>("2022-06-29T18:02:00") => LocalDateTime object
convert<String>("hg") => "hg"
and throw an error if not possible.
This is the code used to do that without any error handling.
/**
* Convert a string to given class type or throw an error if it is not valid
*/
inline fun <reified T> stringToTypeOrError(value: String): T {
val v: T = when (T::class) {
Int::class -> value.toInt() as T
String::class -> value as T
Double::class -> value.toDouble() as T
LocalDateTime::class -> LocalDateTime.parse(value) as T
else -> throw BadRequestException("Does Not Support : $value.")
}
return v
}
But I face a problem when I try to convert string to enums.
For example, if I need to convert to an enum.
convert<Order>("asc") => Order.ASC
For supporting all enums I tried this:
enum class Order { ASC, DESC }
/**
* Convert a string to enum or throw a custom error
*/
inline fun <reified E : Enum<E>> enumValueOrError(value: String): E {
return try {
enumValueOf(value)
} catch (e: java.lang.IllegalArgumentException) {
throw BadRequestException("Does Not Support : $value.")
}
}
/**
* Convert a string to a given class type or throw an error if it is not valid
*/
inline fun <reified T> stringToTypeOrError(value: String): T {
// TODO: Handle all exceptions
val v: T = when (T::class) {
Int::class -> value.toInt() as T
String::class -> value as T
Double::class -> value.toDouble() as T
LocalDateTime::class -> LocalDateTime.parse(value) as T
else -> {
if (T::class.javaClass.isEnum) {
return enumValueOrError<T>(value)
} else {
throw NotImplementedError("Not implemented for type:${T::class.qualifiedName}")
}
}
}
return v
}
build fails saying:
Type argument is not within its bounds: should be subtype of 'Enum<TypeVariable(E)>'
in line return enumValueOrError<T>(value)
Any ideas on how to solve this?
Or how can i pass the generic type T
in enumValueOrError
function
(Without adding each enum inside the when
case)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这种情况与我们通常抑制警告的未检查的演员非常相似。即使在您的情况下,这不是警告,而是错误,Kotlin仍然允许我们抑制它:
此外,您的代码中有一个错误,您可以在其中检查
t :: class.javaclass.isenum
。您应该检查t :: class.java.isenum
。您还可以完全跳过Java反射:t :: class.issubclassof(enum :: class)
。最后,创建如此大的内联函数似乎不是一个好主意。它将极大地影响所得字节码的大小。我建议将此函数分为两个:内部函数,该功能接收
kClass&lt; t&gt;
和Inline Redified函数,仅调用第一个功能。不幸的是,这样,您将失去使用enumvalueof()
实用程序的能力。This case is very similar to unchecked casts where we usually suppress the warning. Even if in your case this is not a warning, but an error, Kotlin still allows us to suppress it:
Additionally, you have a bug in your code where you check for
T::class.javaClass.isEnum
. You should check forT::class.java.isEnum
instead. You can also skip Java reflection entirely with:T::class.isSubclassOf(Enum::class)
.Finally, it seems not a good idea to create such a big inline function. It will greatly affect the size of the resulting bytecode. I suggest to split this function into two: internal function that receives
KClass<T>
and inline reified function that just invokes the first one. Unfortunately, this way you'll lose ability to useenumValueOf()
utility.