Котлин «не ожидал никаких параметров» при попытке вернуть встроенную лямбду

Я пытаюсь написать функцию Kotlin, которая возвращает лямбда, принимая параметр. Я пытаюсь использовать для этого следующий код:

fun <T> makeFunc() : (T.() -> Unit) { return { t: T -> print("Foo") } } 

Примечание. В реальной программе функция более сложна и использует t .

Котлин отвергает это как недействительное, давая ошибку «Ожидаемые без параметров» при t: T

Однако присвоение этой лямбда переменной сначала не отклоняется и отлично работает:

 fun <T> makeFunc() : (T.() -> Unit) { val x = { t: T -> print("Foo") } return x } 

Эти два фрагмента кажутся одинаковыми, так почему это так? Являются ли фигурные скобки после утверждения return интерпретированными как нечто иное, чем лямбда?

Кроме того, IntelliJ сообщает мне, что значение переменной может быть встроено, тогда как это вызывает ошибку.

введите описание изображения здесь

Любопытный момент в дизайне функциональных типов и лямбда-выражений в Котлине.

Фактически, поведение может быть описано в этих двух утверждениях:

  • Именованные значения функциональных типов взаимозаменяемы между обычным функциональным типом типа (A, B) -> C и соответствующим типом функции с первым параметром, преобразованным в приемник A.(B) -> C Эти типы назначаются друг от друга .

    Поэтому, когда вы объявляете переменную, которая вводится как (T) -> Unit , вы можете передать ее или использовать ее там, где ожидается T.() -> Unit , и наоборот.

  • Лямбда-выражения, однако, не могут использоваться таким свободным образом.

    Когда ожидается функция с приемником T.() -> Unit , вы не можете поместить лямбда с параметром T в эту позицию, лямбда должна точно соответствовать сигнатуре, приемник и первый параметр не могут быть преобразованы друг в друга:

    Форма аргумента функции literal или выражение функции должна точно соответствовать расширению соответствующего параметра. Вы не можете передать литерал функции расширения или выражение функции расширения, в котором ожидается функция, и наоборот. Если вы действительно хотите это сделать, измените форму, присвойте литерал переменной или используйте оператор as .

    (из документа, указанного выше )

    Это правило упрощает чтение lambdas: они всегда соответствуют ожидаемому типу. Например, нет никакой двусмысленности между лямбдой с приемником и лямбдой с неявным, которое просто не используется.

Для сравнения:

 fun foo(bar: (A) -> B) = Unit fun baz(qux: A.() -> B) = Unit val f: (A) -> B = { TODO() } val g: A.() -> B = { TODO() } foo(f) // OK foo(g) // OK baz(f) // OK baz(g) // OK // But: foo { a: A -> println(a); TODO() } // OK foo { println(this@foo); TODO() } // Error baz { println(this@baz); TODO() } // OK baz { a: A -> println(a); TODO() } // Error 

В принципе, здесь диагностика IDE неверна. Сообщите об этом в качестве ошибки для трекера Kotlin.

Вы определяете тип функции () -> Unit на приемнике T , для этой функции действительно нет параметра, см. "()" . Ошибка имеет смысл. Поскольку вы определяете тип функции с T качестве приемника, вы можете обратиться к T this :

 fun <T> makeFunc(): (T.() -> Unit) { return { print(this) } } 
Intereting Posts
Разница между ByteArray и Array <Byte> в kotlin Как получить сообщение из идентификатора сообщения в smack. Как вставлять для циклов в шаблоны строк Kotlin Можно ли аннотировать конструктор классов в Котлине Ошибка экземпляра экземпляра в kotlin: умный приведение к типу невозможно Google Assistant SDK отказывается от аутентифицированного канала как «НЕОПРЕДЕЛЕННЫЙ» java.lang.ClassNotFoundException: Не нашел класс «com.my.app.example.Main» по пути: DexPathList Android. установить textSize, чтобы высота соответствовала проценту его высоты макета родителя – возможно? Обратный экземпляр enum непосредственно без класса в Котлине Информация о Facebook не отображается Как использовать `filterValues` на вложенной итерации Hashmap в Котлин? Как реализовать этот интерфейс Java в Котлине? Почему мои проекты IDEA не будут построены? Как выводить / печатать значение в TextView Лучший способ внедрения шаблона посетителя в Котлин