2017-12-16 5 views
4

パラメータを取ってラムダを返すKotlin関数を記述しようとしています。私はこれを行うには、次のようなコードを使用しようとしています:インラインラムダを返そうとするときにKotlinは "期待されたパラメータがありません"

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

注:実際のプログラムでは、機能が複雑で、tを使用しています。

Kotlinはこれを無効として拒否し、t: Tに 'パラメータが必要ありません'というエラーを返します。

はしかし、変数にこのラムダを割り当てるには、最初に拒否されていないと正常に動作します:

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

    return x 
} 

これら二つのスニペットは同じように見えるので、なぜこのような場合は? returnステートメントがラムダ以外のものとして解釈された後の中括弧はありますか?

また、IntelliJは変数の値がインライン化できると伝えますが、これはエラーを引き起こすようです。

enter image description here

答えて

5

Kotlinにおける機能タイプとラムダ式の設計で好奇心旺盛な瞬間があります。

実際には、動作は、これら2つの文で説明することができる。

機能タイプの値が (A, B) -> Cような通常の機能的なタイプとの間に交換可能であり、最初のパラメータを持つ関数の対応するタイプになって名前
  • レシーバA.(B) -> C。これらのタイプはassignable from each otherです。

    したがって、(T) -> Unitと入力された変数を宣言すると、その変数を渡すか、T.() -> Unitが期待される場所で使用することができます。その逆も同様です。

  • しかし、ラムダ式は自由に使用できません。受信機T.() -> Unitと機能が期待されているときは、その位置にTのパラメータでラムダを配置することができない

    、ラムダは正確に署名と一致する必要があり、受信機と最初のパラメータは互いに変換することができない。

    関数リテラル引数または関数式の形状は、対応するパラメータの拡張機能と完全に一致していなければなりません。拡張関数リテラルまたは関数が期待される拡張関数式を渡すことはできません。逆もまた同様です。実際にそれをやりたい場合は、図形を変更したり、リテラルを変数に代入したり、as演算子を使用したりしてください。

    document linked aboveから)この規則は、読みラムダが容易になります:彼らは常に期待されるタイプと一致します。例えば、受信者のあるラムダと暗黙的なitのラムダのあいだにはあいまいさがありますが、それは単に未使用です。

比較:

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([email protected]); TODO() } // Error 

baz { println([email protected]); TODO() } // OK 
baz { a: A -> println(a); TODO() } // Error 

を基本的には、ここで間違っているとIDEの診断です。 report itをKotlinの問題追跡ツールのバグとしてください。

1

() -> Unitファンクションタイプを受信者Tに定義していますが、そのファンクションのパラメータは実際にはありません。"()"を参照してください。エラーは理にかなっています。あなたがその受信機としてTと関数型を定義しているので、あなたはthisによってTを参照することができます。

fun <T> makeFunc(): (T.() -> Unit) { 
    return { 
     print(this) 
    } 
} 
関連する問題