将字符串转换为Kotlin中的任何数据类型

发布于 2025-02-12 01:00:26 字数 2473 浏览 0 评论 0原文

我正在尝试创建一个通用函数,以将任何字符串转换为任何数据类型。 例如,

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

初心未许 2025-02-19 01:00:26

这种情况与我们通常抑制警告的未检查的演员非常相似。即使在您的情况下,这不是警告,而是错误,Kotlin仍然允许我们抑制它:

@Suppress("UPPER_BOUND_VIOLATED")
return enumValueOrError<T>(value)

此外,您的代码中有一个错误,您可以在其中检查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:

@Suppress("UPPER_BOUND_VIOLATED")
return enumValueOrError<T>(value)

Additionally, you have a bug in your code where you check for T::class.javaClass.isEnum. You should check for T::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 use enumValueOf() utility.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文