2017-12-16 14 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

코 틀린에 기능 유형과 람다 식의 디자인에 호기심이 순간이있다.

는 실제로 동작이 두 문장에서 설명 될 수있다 :

    기능 유형

    명명 값 (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) 
    } 
}