微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

未经检查的强制类型转换:尝试以相同的方法将Int或String强制转换为T泛型类型

如何解决未经检查的强制类型转换:尝试以相同的方法将Int或String强制转换为T泛型类型

我对泛型函数(在Java和Kotlin中都是)很陌生。并且我使用了一个允许我恢复列表的功能(感谢SharedPreferences)。这些列表是MutableList<Int><String><Long>,无论......这是我当前正在使用的代码(我使用list.toString()保存了列表,不是空的):

fun <T: Any> restoreList(sharedPrefsKey: String,list: MutableList<T>) {
    savedGame.getString(sharedPrefsKey,null)?.removeSurrounding("[","]")?.split(",")?.forEach { list.add((it.toIntOrNull() ?: it) as T) }
}//"it" is already a String,no need to cast in the "if null" ( ?: ) branch
//warning "Unchecked cast: {Comparable<*> & java.io.Serializable} to T" on "as T"

所以我的目标是知道如何安全地将String强制转换为T(作为参数传递的列表内元素的类型)。现在,我收到警告,想知道我在做什么是否正确。我还应该添加一个in修饰符吗?例如:list: MutableList<in T>吗?

解决方法

科特林(Kotlin)没有union types。 因此,您无法将类型T描述为IntString,因此无法将MutableList<T>描述为MutableList<Int>或{ {1}}

但是,当您执行MutableList<String>时,您什至没有得到,而是一个可变的列表,其中可能包含it.toIntOrNull() ?: it元素和Int的元素(因为编译器无法保证子句将以相同的方式对每个元素进行解析)。因此,编译器尝试推断这种类型(它应该是StringInt的最特定的通用超类型),并且它会得到这种可怕的String类型。这对Comparable<*> & java.io.Serializable可能施加了如此严格的限制,以至于实际上变得毫无用处(就像使用T一样),并且不能用方差注释来解决。

我建议在这里使用附加的功能参数,将MutableList<*>(在拆分之后)转换为所需类型的实例(还要注意,对函数内部传递的参数进行修改是一种代码味道,最好与现有功能合并)与其创建的作用域相同的可变列表):

String

用法:

fun <T> restoreList(sharedPrefsKey: String,converter: (String) -> T): List<T>? =
    savedGame.getString(sharedPrefsKey,null)?.removeSurrounding("[","]")?.split(",")?.map { converter(it) }
,

这是您可以使用化的泛型来执行此操作的方法,当您需要检查泛型类型时,这是必需的。如果您尝试使用when子句中不支持的类型来调用它,则会抛出错误。

inline fun <reified T: Any> restoreList(sharedPrefsKey: String,list: MutableList<T>) {
    val strings = savedGame.getString(sharedPrefsKey,null)
            ?.removeSurrounding("[","]")
            ?.split(",")
    if (strings == null) {
        Log.w("restoreList","No preferences found for key $sharedPrefsKey.")
        return
    }
    when (T::class) {
        String::class -> strings.mapTo(list) { it as T }
        Int::class -> strings.mapNotNullTo(list) { it.toIntOrNull() as? T }
        Long::class -> strings.mapNotNullTo(list) { it.toLongOrNull() as? T }
        // And so on for other types.
        else -> error("Unsupported type ${T::class}.")
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。