Какая разница, если 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>()
}
}
}