:: property.isInitialized无法区分名称相同的方法和属性

时间:2018-08-24 15:55:14

标签: kotlin

我正在创建一个构建器(用于Java兼容),其中context既是私有属性又是公共方法。

private lateinit var context: Context

fun context(appContext: Context) = apply {
    context = appContext
}

fun build(): MySdk {
    // this::context fails to compile because it cannot differentiate between the 
    // method `context()` vs property `context`
    require(this::context.isInitialized) {
        "context == null"
    }

但是我遇到了::context.isInitialized的编译问题,因为它无法区分方法context()与属性context

科特林是否有解决方法?还是我被迫使用唯一的属性/方法名称?

2 个答案:

答案 0 :(得分:2)

这是重载解决方案模棱两可的情况,并且kotlin编译器无法识别您是使用属性还是方法。

这是因为有可调用的引用(::)。在内部,当您使用可调用引用时,它会调用一个方法。

  

Callable references:对函数,属性和   构造函数除了自省程序结构外,还可以   被称为或用作功能类型的实例。

所有可调用引用的公共超类型是KCallable,其中R是返回值类型,它是属性的属性类型,而构造函数是构造函数。

KCallable<out R> // supertype for all callable references

因此,对于函数,类型为KFunction,对于属性,类型为KProperty

interface KFunction<out R> : KCallable<R>, Function<R> (source)
interface KProperty<out R> : KCallable<R> (source)

当您使用类似:的功能时

fun context(appContext: Context) = apply {
    context = appContext
}

可用作功能参考

::context // This is a Function reference i.e. KFunction

使用属性引用时,例如

private lateinit var context: Context
fun something(){
    ::context // this is a property reference, KProperty   
}

可以在需要带有一个参数的函数的地方使用属性引用:

 val strs = listOf("a", "bc", "def")
 println(strs.map(String::length))

因此,并不是Kotlin会强迫您使用不同的属性和函数名称(“尽管不建议”)。只是在这种情况下无法区分

  1. 两者都是KCallable且名称相同
  2. 可以在需要带有一个参数的函数的地方使用属性引用

答案 1 :(得分:1)

您可以通过提供期望的类型来解决属性和方法之间的歧义:

val prop: kotlin.reflect.KProperty0<*> = this::context

A,prop.isInitialized然后给出了编译错误:

This declaration can only be called on a property literal (e.g. 'Foo::bar')

因此,目前看来这不可能。 OTOH,由于错误表明isInitialized已由编译器专门处理,因此很可能可以修复;我建议在http://youtrack.jetbrains.com/上进行报告(在搜索重复项之后)。