2016-08-16 4 views
5

A previous question показывает, как поставить статический инициализатор внутри класса, используя его companion object. Я пытаюсь найти способ добавить статический инициализатор на уровне пакета, но, похоже, у пакетов нет сопутствующего объекта.Как написать статический инициализатор уровня пакета в Котлине?

// compiler error: Modifier 'companion' is not applicable inside 'file' 
companion object { init { println("Loaded!") } } 
fun main(args: Array<String>) { println("run!") } 

Я пробовал другие варианты, которые, возможно, уже имело смысл (init сам по себе, static), и я знаю, как обходной путь я могу использовать одноразовые val как в

val static_init = { 
    println("ugly workaround") 
}() 

но есть ли чистый, официальный способ добиться того же результата?


Edit: Как @mfulton26's answer упоминает, что нет такого понятия, как функция уровня пакета действительно в JVM. За кулисами компилятор kotlin - wrapping any free functions, including main in a class. Я пытаюсь добавить статический инициализатор в , что класс - класс, создаваемый kotlin для бесплатных функций, объявленных в файле.

+0

Почему бы не использовать 'main' для инициализации? – mfulton26

+0

Потому что я выбрал плохой пример с игрушкой. Представьте себе файл, полный связанных свободных функций, которые зависят от некоторой общей инициализации. Возможно, я мог бы просто обернуть их в названный «объект», но большая красота котлина, как правило, не вынуждена делать подобные вещи. – Dan

+0

Получил. К сожалению, я не знаю, как это сделать, кроме вашего обходного пути или варианта. например 'val static_init = run {println (" обходной путь ")}' или 'val static_init = object {init {println (" обходной путь ")}}'. – mfulton26

ответ

4

В настоящее время не существует никакого способа, чтобы добавить код на статический конструктор, созданный для классов файлов Котлин, только верхнего уровня собственности туда поступают инициализаторы. Это звучит как запрос функции, так что теперь есть проблема для отслеживания этого: KT-13486 Блоки «init» на уровне пакета

Другим обходным решением является размещение инициализации в частном/внутреннем объекте верхнего уровня и ссылка на этот объект в этих функциях которые зависят от эффекта этой инициализации. Объекты инициализируются лениво, когда они ссылаются в первый раз.

fun dependsOnState(arg: Int) = State.run { 
    arg + value 
} 

private object State { 
    val value: Int 
    init { 
     value = 42 
     println("State was initialized") 
    } 
} 
+0

В Kotlin 1.1 вы можете использовать скрипт Kotlin (.kts), который будет запускать код без необходимости объявления. Это похоже на то, чего хочет ассер. – Jire

3

Как уже упоминалось, вам нужно свойство с чем-то, что будет работать на инициализацию:

val x = run { 
    println("The package class has loaded") 
} 
0

Я обошел его, используя свойство Backing на верхнем уровне под файлом Kotlin. Kotlin Docs: Backing Properties

private var _table: Map<String, Int>? = null 
public val table: Map<String, Int> 
    get() { 
     if (_table == null) { 
      _table = HashMap() // Type parameters are inferred 
      // .... some other initialising code here 
     } 
     return _table ?: throw AssertionError("Set to null by another thread") 
    } 
+0

Если вам нужно только одно, лениво инициализированное значение, подобное этому, у Kotlin есть встроенное для вас: 'val table: MutableMap by lazy (:: HashMap)' – Dan

Смежные вопросы