Почему этот inline job не компилируется, когда его lambda работает внутри Runnable?
job помечен inline и возвращает Runnable, который вызывает встроенную lambda внутри другой lambda (executeTask). Код не компилируется. Поправьте сигнатуры так, чтобы он собирался, сохранив inline там, где он полезен.
fun executeTask(task: () -> Unit) {
println("before task"); task(); println("after task")
}
inline fun job(job: () -> Unit): Runnable {
return Runnable { executeTask(job) } // не компилируется
}
fun main() {
val executor = Executors.newSingleThreadExecutor()
executor.submit(job { println("hello task") })
}
Найдите и исправьте ошибку.
Встроенная lambda может сделать non-local return, что нелегально внутри вложенного Runnable. Пометьте параметр crossinline job: () -> Unit, чтобы запретить такой return и разрешить запуск внутри Runnable. Либо уберите inline у job.
- ✗Считать, что любую встроенную lambda можно вызвать откуда угодно, включая вложенный объект
- ✗Хвататься за
noinline, когда lambda на самом деле нуженcrossinline - ✗Винить Java SAM-преобразование вместо правила non-local return
- →Чем
crossinlineотличается отnoinlineдля параметра lambda? - →Почему non-local return нелегален именно внутри тела
Runnable?
Баг
job помечен inline, поэтому его lambda-параметр по умолчанию допускает non-local return. Но lambda вызывается внутри объекта Runnable — отдельного контекста выполнения, где non-local return нелегален. Компилятор отвергает это.
inline fun job(job: () -> Unit): Runnable {
return Runnable { executeTask(job) } // ❌ job мог бы сделать non-local return
}
Исправление
Пометьте параметр crossinline. Это запрещает non-local return, поэтому lambda разрешено выполнять внутри Runnable, а тело job остаётся встроенным.
inline fun job(crossinline job: () -> Unit): Runnable {
return Runnable { executeTask { job() } } // ✅
}
Альтернатива — убрать inline у job целиком: тогда lambda становится обычным объектом и проблема non-local return исчезает.