В чем разница между основной и регулярной функцией?

Kotlin позволяет мне создавать две основные функции(). Но не позволяет использовать две функции myfun().

  • Что особенного в main()? Существуют ли другие специальные функции?
  • Могу ли я создать две статические функции myfun() в одном пакете? Я хочу, чтобы у них была область файлов, такая как main.

Test1.kt:

package start

fun main(args: Array<String>) {
}

fun myfun(args: Array<String>) {
}

Test2.kt:

package start
// OK!
fun main(args: Array<String>) {
}
// Error! Conflicting overloads
fun myfun(args: Array<String>) {
}

Ответ 1

Kotlin позволяет иметь несколько main функций верхнего уровня в одном пакете по практическим соображениям - чтобы можно было иметь точку входа в каждом файле, не перемещая эти файлы в разные пакеты.

Это возможно, потому что каждый.kt файл с членами верхнего уровня скомпилирован в соответствующий файл класса, поэтому эти main функции не конфликтуют, потому что они находятся в отдельных файлах классов.

Почему это разрешено для main функций, а не для других функций верхнего уровня? Наличие нескольких функций с тем же именем и подписью в одном пакете делает невозможным их отличить при вызове из Котлина. Это не проблема для main функции, поскольку, когда она используется как точка входа для программы, она должна указывать имя класса, в котором оно расположено.

Ответ 2

Что особенного в main()? Существуют ли другие специальные функции?

Чтобы запустить Java-программу, вам нужно

  1. файл класса,
  2. static void main(String[]) в этом файле класса.

Поэтому извне пакета вы сможете запустить любой из этих main методов.

Однако, если вы попытаетесь вызвать main метод из другого файла Kotlin внутри пакета, вы получите сообщение об ошибке, потому что Котлин не может устранить один метод из другого.

Вы можете вызвать любой из них из Java, как вам будет угодно, потому что они скомпилированы в разных файлах классов (см. Далее).

Могу ли я создать две статические функции myfun() в одном пакете?

Вы не можете определить два метода верхнего уровня с тем же именем в одном пакете в Котлине (с указанным выше исключением).

Это то, что компилирует ваш код:

public final class Test1Kt {
   public static final void main(@NotNull String[] args) { /* ... */ }

   public static final void myFun(@NotNull String[] args) { /* ... */ }
}

public final class Test2Kt {
   public static final void main(@NotNull String[] args) { /* ... */ }

   public static final void myFun(@NotNull String[] args) { /* ... */ }
}

Что касается JVM, все эти методы могут сосуществовать в мире. Но это деталь реализации Котлина.

Напоминаем, что приложения Kotlin запускаются на JVM. Притвориться, что единственным инструментом является Kotlin, и вы не можете использовать Java, возможно, вы пишете кросс-платформенный модуль Kotlin. Как вы можете использовать две функции верхнего уровня с тем же именем? Как бы вы выбрали, какой из них назвать? Опять же, вы получите ошибку, потому что Котлин не может устранить один метод из другого.

Изменение: Как отметил @Todd, в прошлом это поведение было еще более жестким: почему Kotlin lang допускает только одну главную функцию в проекте?

Ответ 3

Что касается вопроса о том, как использовать функции с файловыми областями, то по умолчанию функции верхнего уровня (те, которые не объявлены в классе) являются public, что означает, что их подписи должны быть уникальными, включая имя пакета. Вы можете делать локальные функции в файле, а не в пакете, путем префикса их с помощью private модификатора, например, в каждом файле:

private fun myfun(args: Array<String>) {
    // method body here
}