generics - 为 kotlin 泛型设置默认值

标签 generics kotlin

我有这个扩展功能:

fun <T : View> Activity.bind(idRes: Int): Lazy<T> = lazy { findViewById<T>(idRes) }

如您所见,我的通用 T应该是 View或后代。

每当我想使用它来获取 View 后代时,我都会执行以下选项之一:
val textView1 by bind<TextView>(R.id.text_view_1)
val textView2: TextView by bind(R.id.text_view_2)

很不错,但是现在让我们看看问题,有时我不需要具体的类型,我只需要View,例如当我想设置一个点击监听器时,所以我必须这样做:
val view1 by bind<View>(R.id.view_1)
val view2: View by bind(R.id.view_2)

我想知道一种删除显式类型 View 的方法, 让 kotlin 编译器看到它是我定义后的默认值 T : View , 是否可以?

换句话说,我想要这个:
val textView1 by bind<TextView>(R.id.text_view_1)
val textView2: TextView by bind(R.id.text_view_2)
val view by bind(R.id.view_xyz) // kotlin compiler understands it is a View

我确实尝试过:
fun Activity.bind(idRes: Int): Lazy<View> = lazy { findViewById<View>(idRes) }

fun <T : View> Activity.bind(idRes: Int): Lazy<T> = lazy { findViewById<T>(idRes) }

但我得到了:
Platform declaration clash: The following declarations have the same JVM signature

由于泛型类型删除,什么是有意义的……

我想知道一个不涉及其他方法的解决方案,如 fun Activity.bindView...因为我想让 API 尽可能简单。

附言synthetic选项有几个错误,这就是我们使用这个惰性绑定(bind)的原因是远离它。

最佳答案

Kotlin 编译器总是会推断出最具体的泛型类型,并且没有“默认”类型参数之类的东西,因此您必须创建额外的函数。您可以使用 JvmName解决平台声明崩溃的注释:

fun <T> foo(): T? = null

@JvmName("foo0")
fun foo(): Any? = null

fun main() {
    foo<Nothing>()
    foo()
}

关于generics - 为 kotlin 泛型设置默认值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60064683/

相关文章:

java - 嵌套在泛型类中的私有(private)类也应该是泛型吗?

java - 为什么边界在 Java 中如此奇怪?

android - 带有 2 个参数的自定义绑定(bind)适配器和 requireAll 抛出 KaptExecution

android - 为什么必须将 "Dispatchers.Main"添加到 Activity CoroutineScope 实现的根作业中?

java - 在 Kotlin 中返回 Fragment 实例 @JvmStatic

arrays - Kotlin 中的二维 Int 数组

c# - 如何创建具有相同签名但不同泛型类型的扩展方法?

scala - 从没有运行时强制转换的泛型函数返回 case 类的副本

java - 在三元中使用无界泛化静态函数时如何避免未经检查的强制转换?

java - 为什么调用 put() 在使用类似代码在 Java 中编译时无法在 Kotlin 中编译