Какое значение имеет наличие Companion.foo в объекте-компаньоне? - PullRequest
1 голос
/ 15 октября 2019

В 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 Ответ

2 голосов
/ 15 октября 2019

В вашем примере определение 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>()
        }
    }
}
...