Kotlin绑定类型参数扩展重载

时间:2018-07-03 13:27:24

标签: generics kotlin overloading

是否可以根据扩展函数的绑定类型参数来对其进行重载?例如:

abstract class BaseActivity : AppCompatActivity() {

    fun <T : Drawable> Int.get(): T? 
        = ContextCompat.getDrawable(this@BaseActivity, this@get) as T?
    fun <T : View> Int.get(): T 
        = findViewById(this)

}

用法示例:

R.id.webView.get<WebView>() // finds webView
R.drawable.image.get<Drawable>() // gets drawable from resources

(Android代码与该问题无关,这就是我所拥有的)

但这给了我错误:

Conflicting overloads: public fun <T : Drawable> Int.get(): T? defined in xxx.BaseActivity, 
public final fun <T : View> Int.get(): T defined in xxx.BaseActivity

不可能吗?

3 个答案:

答案 0 :(得分:1)

使用@JvmName解决平台声明冲突的“正常”方法在这里行不通:Kotlin允许按值参数的类型而不是按类型参数的范围进行重载。

可以通过添加无用的值参数和(与无用的)默认值来解决此问题。

// unchanged
fun <T : Drawable> Int.get(): T? =
        ContextCompat.getDrawable(this@BaseActivity, this@get) as T?

// added a parameter
fun <T : View> Int.get(dummy: Nothing? = null): T =
        findViewById(this)

一些不相关的注释:

  • 此类小方法应为inline,尤其是那些具有默认参数值的方法
  • findViewById可以替换为Kotlin Android extensions
  • Anko库具有许多有用的扩展和快捷方式,包括用于获取资源甚至从没有XML的代码中构建布局的扩展和快捷方式。

答案 1 :(得分:0)

在删除泛型之后,这两个函数将编译为相同的函数签名。

例如,它可能是这样的:

@NotNull
public final String get() {
  ...
}

编译器无法知道要调用哪个函数。

对此的一种解决方案可以是类型参数化。

    interface Some
    interface Other

    inline fun <reified T> get() = when (T::class) {
        Some::class -> "hey"
        Other::class -> null
        else -> throw UnsupportedOperationException()
    }

但是,您必须取消类型限制。

答案 2 :(得分:0)

  

是否有可能根据扩展函数的绑定类型参数对其进行重载?

一般来说,是的。问题在于参数仅出现在返回类型中,而Java规则(在这方面Kotlin遵循Java的规则)不允许基于其返回类型进行重载,因为返回类型不用于重载解析。这个决定是在泛型出现在Java中之前做出的,因为这样编译器将永远无法选择更具体的方法。此后可以进行修改,但不是。

如果您有一个T 参数,它将起作用。