Ответ 1
Во-первых, у меня возникают проблемы с изображением того, что подразумевается под "такими случаями". У меня есть общее представление о том, что проблема, но не может придумать хороший пример.
Вот пример:
interface SomeInterface {
fun someFunction(): Unit
}
inline fun someInterfaceBy(f: () -> Unit): SomeInterface {
return object : SomeInterface {
override fun someFunction() = f()
// ^^^
// Error: Can't inline 'f' here: it may contain non-local returns.
// Add 'crossinline' modifier to parameter declaration 'f'.
}
}
Здесь функция, которая передается в someInterfaceBy { ... }
, встроена в анонимный класс, реализующий SomeInterface
. Компиляция каждого сайта-клиента someInterfaceBy
создает новый класс с другой реализацией someFunction()
.
Чтобы узнать, что может пойти не так, рассмотрите вызов someInterfaceBy { ... }
:
fun foo() {
val i = someInterfaceBy { return }
// do something with `i`
}
Внутри встроенной лямбды return
является нелокальным и на самом деле означает возврат из foo
. Но поскольку лямбда не вызывается и не протекает в объект i
, возврат из foo
может быть абсолютно бессмысленным: что, если i.someFunction()
(и, следовательно, лямбда) вызывается после того, как foo
уже возвращено или даже в другой поток?
В общем случае "такие случаи" означают функции inline
, которые вызывают их функциональные параметры не в их собственных телах (эффективно, то есть принимая во внимание другие встроенные функции), но внутри некоторых других функций, которые они объявляют, например, в нестрочных лямбдах и анонимных объектов.
Во-вторых, фраза "Чтобы указать это", можно читать несколькими способами. Чтобы указать, что? Что конкретный случай не допускается? Что это разрешено? Этот нелокальный поток управления в определенном определении функции (или не разрешен)?
Именно так проблема, описанная выше, исправлена в дизайне языка Котлина: всякий раз, когда функция inline
намеревается встроить свой функциональный параметр где-нибудь, где его можно было бы не вызывать на месте, но хранить и вызывать позже, параметр функции inline
следует пометить как crossinline
, указывая на то, что в lambdas, переданном здесь, не допускается нелокальный поток управления.