Comments 10
Спасибо за статью и подробное объяснение!
Добавлю небольшое уточнение по поводу crossinline.
private inline fun crossInlineFun(crossinline body: () -> String) {
val func = {
"crossInline func code, " + body.invoke()
}
regularFun(func)
}
В этом примере нужен crossinline, так как в передаваемой лямбде-параметре body на стороне вызывающей функции могут быть non-local returns, и поэтому body нельзя передавать в другой контекст исполнения (в лямбду func). Чтобы исправить это, можно либо отменить инлайнинг body (добавив noinline), либо запретив использовать non-local returns внутри body (добавив crossinline). В этом примере более предпочтителен вариант с crossinline, так как он позволяет всё-таки заинлайнить body.
noinline же полезен в том случае, когда, например, нужно работать с лямбдой-параметром в inline функции как с обычной переменной или передать в качестве параметра в "не inline" функцию.
private inline fun crossInlineFun(noinline body: () -> String) {
val someFunc = body
regularFun(func)
}
Здесь отменяется илнайнинг body, поэтому для него создаётся инстанс анонимного класса, и с ним можно работать как с обычной переменной.
Этот пример очень хорошо показывает, что inline функции никак не помогают нам экономить количество методов.
Это неправда. Помогают, если включена минификация. Если инлайн-метод не используется из джавы, то он будет вырезан.
Не надо пытаться помогать JIT компилятору делать его работу)
Суть инлайнинга не в экономии методов. Косвенно он может их сокращать, но задуман он совсем не для этого.
Это никак не противоречит тому, что я сказал. Утверждение в статье от этого правдой не становится.
Вот честно, тезис о том, что inline экономит количество методов, только от вас услышал. Обычно говорят, что он уменьшает количество вызовов, что может быть хорошо в циклах.
Лямбда аргументы inline функции прозрачны для контекстов suspend и @Composable
suspend fun test() = Unit
fun repeat1(i: Int, action: (Int) -> Unit): Unit = TODO()
suspend fun context() {
repeat1(5) {
test()
}
}Такой код с repeat без inline не скомпилируется, нужно чтобы было action: suspend (Int) -> Unit. А потом появляется Compose и нужна +1 перегрузка. С inline одна декларация работает сразу с любыми вызовами
Kotlin под капотом: inline функции