Какая разница, если Companion.foo находится в объекте-компаньоне?

В Kotlin, если у меня есть функция в сопутствующем объекте с Companion. в качестве префикса (Companion.foo), какая разница по сравнению с foo внутри объекта-компаньона?

Я заметил, что в следующем коде Companion.foo сделает его невидимым для внешней области, но по-прежнему видимым для функций внутри того же сопутствующего объекта.

Вы можете найти фрагмент кода по адресу: https://pl.kotl.in/t6FvM6ni6

fun main() {
    A.foo() // compiler complains "unresolved reference"
    A.bar()
    B.foo()
}

class A {
    companion object {
        fun Companion.foo() {
            println("hello in A")
        }

        fun bar() {
            foo()
        }
    }
}

class B {
    companion object {
        fun foo() {
            println("hello in B")
        }
    }
}

Есть еще отличия? НаходятсяA.Companion.foo а также A.fooто же самое кроме видимости? Это способ инкапсулировать методы в сопутствующий объект?


Обновление 1

В моем реальном проекте я звоню inline функция от другого inlineв сопутствующем объекте, поэтому модификаторы доступа использовать нельзя. Но я все еще хотел бы скрытьfoo если возможно.

class C {
    companion object {
        inline fun <reified T> Companion.foo() {
            println("hello in A")
        }

        inline fun bar() {
            foo<String>()
        }
    }
}

1 ответ

В вашем примере определение Companion.foo()является расширением в качестве члена. В этом случае вы определяете расширение в том же типеA.Companionкак тип расширения. Это бесполезно.

В следующем примере показана концепция расширения как члена с двумя разными классами. Пример без компаньонов, потому что он не имеет значения для концепции.

class A 

class B {
    fun A.foo() {
        println("Extension for A, only visible in B")
        println("Function has two 'this' references: ${this} and ${this@B}")
    }

    fun bar() {
        val a = A()
        a.foo() // this function call is only possible in the context of `B`
    }
}

fun main() {
    val a = A()
    a.foo() // compile error
}

Все сказано, двое foo()функция в вашем примере имеет разные подписи внутри. Нормальная функцияfoo()- это простой метод для сопутствующего объекта без параметров. Функция расширенияCompanion.foo() - это метод сопутствующего объекта, но с дополнительным параметром для второго this Справка.

Чтобы инкапсулировать методы в компаньонах, просто поместите private модификатор перед функцией.

Если вам нужна встроенная функция, используйте internal а также @PublishedApi чтобы скрыть функцию от публичного API.

class C {
    companion object {
        @PublishedApi
        internal inline fun <reified T> foo() {
            println("hello in A")
        }

        inline fun bar() {
            foo<String>()
        }
    }
}
Другие вопросы по тегам