How does Kotlin disambiguate function calls, constructors, companion objects and invocation overloads? In Kotlin 1.3.11, I can declare two homonymous members in the same scope:

fun main(args: Array<String>) {
    val test = object {
        operator fun invoke() = println("test invocation")
    }

    test() // Prints: "test invocation"

    // I think this should fail to compile, but it works
    fun test() = println("test function")

    test() // Prints: "test function"
}

你可能会认为它使用了最新的声明,但事实并非如此!

fun main(args: Array<String>) {
    fun test() = println("test function")

    val test = object {
        operator fun invoke() = println("test invocation")
    }

    test() // Prints: "test function"
}

但与Scope之间也存在一些奇怪的交互.如果我将函数声明移到外部:

fun test() = println("test function")

fun main(args: Array<String>) {
    val test = object {
        operator fun invoke() = println("test invocation")
    }

    test() // Prints "test invocation"
}

Similarly, if I move the object outside, this also compiles:

val test = object {
    operator fun invoke() = println("test invocation")
}

fun main(args: Array<String>) {
    fun test() = println("test function")
    test() // Prints: "test function"
}

我也可以把它们都搬到外面:

val test = object {
    operator fun invoke() = println("test invocation")
}

fun test() = println("test function")

fun main(args: Array<String>) {
    test() // Prints: "test function"
}

但如果我使用类名重载test,它不会编译:

class test {} // Does not compile

fun test() = println("test function")

val test = object {
    operator fun invoke() = println("test invocation")
}

试图编译此程序会导致以下错误:

Error:(1, 6) Conflicting overloads: public fun test(): Unit defined in root package in file Simplest version.kt, public constructor test() defined in test, public val test: Any defined in root package in file Simplest version.kt, public final class test defined in root package in file Simplest version.kt
Error:(1, 6) Conflicting declarations: public fun test(): Unit, public constructor test(), public val test: Any, public final class test
Error:(2, 0) Conflicting overloads: public fun test(): Unit defined in root package in file Simplest version.kt, public constructor test() defined in test, public val test: Any defined in root package in file Simplest version.kt, public final class test defined in root package in file Simplest version.kt
Error:(3, 4) Conflicting declarations: public fun test(): Unit, public constructor test(), public val test: Any, public final class test

However it does compile when using a nested scope:

class test {
    constructor() {
        println("test constructor")
    }
}

fun main(args: Array<String>) {
    fun test() = println("test function")

    val test = object {
        operator fun invoke() = println("test invocation")
    }

    test() // Prints: "test function"
}

There is also some ambiguity between companion objects and constructors:

class test {
    constructor() {
        println("test constructor")
    }

    companion object {
        operator fun invoke() = println("test companion invocation")
    }
}

fun main(args: Array<String>) {
    test() // Prints: "test constructor"
}

Somehow, the following example also compiles:

class test {
    constructor() {
        println("test constructor")
    }

    companion object {
        operator fun invoke() = println("test companion invocation")
    }
}

fun main(args: Array<String>) {
    test() // Prints: "test constructor"

    val test = object {
        operator fun invoke() = println("test invocation")
    }

    test() // Prints: "test invocation"

    fun test() = println("test function")

    test() // Prints: "test function"
}

This is even less intuitive:

class test {
    constructor() {
        println("test constructor")
    }

    companion object {
        operator fun invoke() = println("test companion invocation")
    }

    operator fun invoke() = println("test invocation overload")
}

fun main(args: Array<String>) {
    val test = test() // Prints: "test constructor"

    val test1 = test() // Prints: "test invocation overload"
}

What are the rules for overloading named members and why will the Kotlin compiler accept invocable variables and homonymous functions in the same scope, but not in the presence of a homonymous class (in certain cases, but not others)? Also, how does invoke work in the presence of a scoped constructor or companion object with the same call site syntax?

推荐答案

From what I see in kotlin-spec.asc#order-of-evaluation there are three rules at play (unfortunately the text in incomplete in some points):

  1. 具有最佳类型匹配的表达式(不出现在您的问题中)
  2. local declaration takes precedence over non-local. This is also called shadowing.

    简单名称是单个标识符.其含义取决于该名称的符号在范围内.如果范围内只有具有该名称的符号,则简单名称指代它.如果范围内有多个具有此名称的符号,则非正式地 Select 其声明与简单名称的出现"最接近"的符号.有关更精确的规则,请参见待办事项

  3. if all symbols of same name are at the same level functions take precedence over properties with invoke

    实际订单是

    • 函数描述符(包含类中的fun foo())
    • dispatch receiver (see declaring-extensions-as-members)
      • 如果调度接收方和扩展接收方的成员之间存在名称冲突,则扩展接收方优先.

    • 分机接收器(fun A.foo() defined outside of the class)
    • 任务优先级排序器(据我所知,它会按类型找到最佳匹配项,或者在有一些默认参数的情况下找到最佳匹配项.我假设这是invoke所属的类别)

如果将此应用于上一个示例:

class test {
    constructor() {
        println("test constructor")
    }

    companion object {
        operator fun invoke() = println("test companion invocation")
    }

    operator fun invoke() = println("test invocation overload")
}

fun main(args: Array<String>) {
    val test = test() // Prints: "test constructor" //you create a local variable with invoke. Constructor is executed.

    val test1 = test() // Prints: "test invocation overload" //invoke of the local variable is called.

    test.Companion() //access the companions' invoke which is shadowed by the other invoke.
}

Kotlin相关问答推荐

在Jetpack Compose中创建波浪式文本动画:顺序中断问题

为什么使用 return instance ?: synchronized(this) { instance ?: PreferenceParameterState(context) } 时无法获得单例?

为什么在jacksonObjectMapper上将DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES设置为false无效?

Kotlin:我可以将函数分配给 main 的伴随对象中的变量吗?

Kotlin:我可以将函数分配给 main 的伴随对象中的变量吗?

Kotlin 函数有 2 个参数用于对 Map 或 List 进行排序

mutableStateOf 在 Jetpack Compose 中不记住 API 的情况下保持重组后的值

kotlin 如何决定 lambda 中的参数名称?

在 kotlin 中写入 parcer 可空值

@InlineOnly 注释是什么意思?

使用 Hilt 注入 CoroutineWorker

如何在调试中修复 ClassNotFoundException: kotlinx.coroutines.debug.AgentPremain?

Intellij 显示 build.gradle.kts 中的每一行都是红色的

Android插件2.2.0-alpha1无法使用Kotlin编译

Android 上的 Kotlin:将map到list

Java Integer.MAX_VALUE 与 Kotlin Int.MAX_VALUE

android Room 将 Null 作为非 Null 类型返回

Android Studio - java.io.IOException:无法生成 v1 签名

为什么 Kotlin 会收到这样的 UndeclaredThrowableException 而不是 ParseException?

Dagger 2 androidx fragment不兼容类型