Есть ли более чистый способ установить переменную верхнего уровня позже в коде, не превращая ее в переменную lateinit? - PullRequest
1 голос
/ 27 апреля 2020

Итак, я хочу добиться, чтобы переменная верхнего уровня была установлена ​​через некоторое время в основной функции, но я не хочу делать это переменным lateinit, которая, безусловно, нарушает функциональность переменной Extension.

Например, этот код не работает, поскольку переменные расширения не поддерживают модификатор lateinit:

lateinit var Dispatchers.Konvironment: MainCoroutineDispatcher
    private set

fun main() {
    ...
    Dispatchers.Konvironment = ArbitraryMainDispatcher(Thread.currentThread()) { queue.add(it) }
    ...
}

Итак, я наконец-то придумал использовать фиктивную переменную и реализовать метод получения переменная val.

val Dispatchers.Konvironment: MainCoroutineDispatcher
    get() = dispatcher

private lateinit var dispatcher: MainCoroutineDispatcher

fun main() {
    ...
    dispatcher = ArbitraryMainDispatcher(Thread.currentThread()) { queue.add(it) }
    ...
}

Но это, конечно, не чистый способ сделать это. Это выглядит некрасиво (я sh), создание нескольких переменных в структуре верхнего уровня - не очень чистая архитектура.

Так есть ли какие-нибудь возможные обходные пути? Вроде как ленивая инициализация некоторыми делегатами или что-то в этом роде.

1 Ответ

1 голос
/ 27 апреля 2020

Ну, частично ответив на ваш вопрос:

var Dispatchers.Konvironment: MainCoroutineDispatcher
    get() = dispatcher
    private set(value) {
        dispatcher = value
    }

private lateinit var dispatcher: MainCoroutineDispatcher

fun main() {
    ...
    Dispatchers.Konvironment = ArbitraryMainDispatcher(Thread.currentThread()) { queue.add(it) }
    ...
}

даст вам желаемый способ присвоения значения. Однако нет способа избавиться от этой дополнительной переменной lazyinit.

Расширения - это не более чем просто синтаксический сахар Kotlin для методов stati c, которые принимают экземпляр расширенного класса в качестве одного из аргументов и выполняют некоторое действие. Если вы знакомы с Java, то, например, эти расширения:

// Extensions.kt

fun Foo.extendedAction() {
    println(this)
}

var Foo.extendedBar: Bar
    get() = this.bar
    set(value) {
        this.bar = value
    }

скрыты под этими методами в Java:

public class ExtensionsKt {
    public static final void extendedAction(Foo foo) {
        System.out.println(foo);
    }

    public static final Bar getExtendedBar(Foo foo) {
        return foo.getBar();
    }

    public static final Bar setExtendedBar(Foo foo, Bar bar) {
        foo.setBar(bar);
    }
}

Заключение, которое может быть Из вышесказанного следует, что расширения на самом деле не добавляют ничего к сигнатурам расширенных классов, они просто украшают их дополнительными функциями. Или, как указано в документах :

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

Таким образом, вы можете видеть, если только dispatcher как-то уже существует в Dispatchers, вы не можете делать то, что вы хотите, не предоставив внешнюю переменную «поддержки», на значение которой может ссылаться расширение.

...