Вызвать встроенную лямбду с другим встроенным аргументом лямбда - PullRequest
0 голосов
/ 14 ноября 2018

Я пытаюсь сделать эту функцию Котлина более высокого порядка:

private inline fun <T> reentrant(entered: ThreadLocal<Boolean>, block: () -> T, enter: (() -> T) -> T) =
    if (entered.get()) block()
    else {
        try {
            entered.set(true)
            enter(block)
        } finally {
            entered.set(false)
        }
    }

Для использования, например, так:

reentrant(fooing, block) { b ->
  try {
    log("Entering a state of foo")
    b()
    // sidenote: while writing this question it dawned on me,
    //           that i could just calll the captured `block` here,
    //           as a workaround
  } finally {
    log("Foo nevermore")
  }
}

Однако, по-видимому, конструкция enter(block) не допускается (Illegal usage of inline parameter block).

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

1 Ответ

0 голосов
/ 14 ноября 2018

Вы получаете ту же ошибку, если вы делаете что-то вроде val x = block.Если вы попытаетесь декомпилировать этот Kotlin в байт-код, вы увидите самую последнюю ошибку:

Trying to access skipped parameter

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

Это объясняется более подробно здесь .Когда параметр функции встроен, объект Function не создается.Интересно, если в своем вопросе вы подразумеваете: «Почему компилятор не вставляет enter, а затем вставляет block в это?»И я думаю, причина в том, что это предполагает, что все, что enter делает, это вызывает block.Но что, если это не так?Что если он хочет сохранить ссылку на него, например, в списке функций, которые будут вызываться в будущем?Он не мог этого сделать, так как для него не существует Function объекта для ссылки.

...