gpt4 book ai didi

kotlin - Kotlin 如何调度调用运算符?

转载 作者:IT老高 更新时间:2023-10-28 13:36:08 24 4
gpt4 key购买 nike

Kotlin 如何消除函数调用、构造函数、伴生对象和调用重载的歧义?在 Kotlin 1.3.11 中,我可以在同一个作用域内声明两个同名成员:

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"
}

但也有一些奇怪的作用域交互。如果我将函数声明移到外面:

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

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

test() // Prints "test invocation"
}

同样,如果我将对象移到外面,这也会编译:

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

但是在使用嵌套作用域时它确实可以编译:

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"
}

伴随对象和构造函数之间也存在一些歧义:

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

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

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

不知何故,下面的例子也可以编译:

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"
}

这更不直观:

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"
}

重载命名成员的规则是什么?为什么 Kotlin 编译器会接受同一作用域内的可调用变量和同名函数,但不接受同名类的存在(在某些情况下,但在其他情况下不接受)?此外,在存在具有相同调用站点语法的作用域构造函数或伴随对象的情况下,调用如何工作?

最佳答案

根据我在 kotlin-spec.asc#order-of-evaluation 中看到的内容有三个规则在起作用(不幸的是,有些地方的文字不完整):

  1. 具有最佳类型匹配的表达式(不会出现在您的问题中)
  2. 本地声明优先于非本地声明。这也称为阴影。

    A simple name is a single identifier. Its meaning depends on what symbol with that name are in scope. If only on symbols with that name is in scope, then the simple name refers to it. If there are multiple symbols with this name are in scope, then, informally, the symbol whose declaration is "closest" to the occurrence of the simple name is selected. For more precise rules, see TODO

  3. 如果所有同名符号都在同一级别,则函数优先于带有调用的属性

    实际顺序是

    • function descriptor (fun foo() in the containing class)
    • dispatch receiver (see declaring-extensions-as-members)
      • In case of a name conflict between the members of the dispatch receiver and the extension receiver, the extension receiver takes precedence.

    • 扩展接收器(fun A.foo() 在类之外定义)
    • Task Prioritizer(据我了解,根据类型找到最佳匹配,或者例如当有一些默认参数时。我认为这是 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 - Kotlin 如何调度调用运算符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54045644/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com