인터페이스 대신 람다 전달
인터페이스를 만들었습니다.
interface ProgressListener {
fun transferred(bytesUploaded: Long)
}
그러나 람다가 아닌 익명 클래스로만 사용할 수 있습니다.
dataManager.createAndSubmitSendIt(title, message,
object : ProgressListener {
override fun transferred(bytesUploaded: Long) {
System.out.println(bytesUploaded.toString())
}
})
나는 그것을 람다로 대체 할 가능성이 있어야한다고 생각합니다.
dataManager.createAndSubmitSendIt(title, message, {System.out.println(it.toString())})
하지만 오류가 발생합니다. 유형 불일치; 필수 - ProgressListener, 발견됨 - () -> 단위?
내가 무엇을 잘못하고 있지?
@zsmb13이 말했듯이 SAM 변환은 Java 인터페이스에서만 지원됩니다.
그래도 작동하도록 확장 기능을 만들 수 있습니다.
// Assuming the type of dataManager is DataManager.
fun DataManager.createAndSubmitSendIt(title: String,
message: String,
progressListener: (Long) -> Unit) {
createAndSubmitSendIt(title, message,
object : ProgressListener {
override fun transferred(bytesUploaded: Long) {
progressListener(bytesUploaded)
}
})
}
Kotlin은 Java 인터페이스에 대한 SAM 변환만 지원합니다.
... 이 기능은 Java interop에서만 작동합니다. Kotlin에는 적절한 함수 유형이 있으므로 함수를 Kotlin 인터페이스 구현으로 자동 변환할 필요가 없으므로 지원되지 않습니다.
-- 공식 문서
매개변수에 람다를 사용하려면 함수가 인터페이스 대신 함수 매개변수를 사용하도록 합니다. (적어도 현재로서는 Kotlin 인터페이스에 대한 SAM 변환 지원에 대한 논의가 진행 중이며 Kotlin 1.1 라이브 스트림에서 가능한 미래 기능 중 하나였습니다.)
파티에 조금 늦었습니다. 인터페이스를 만드는 대신 다음과 같이 데이터 관리자의 인터페이스 대신 함수를 직접 사용하여 컴파일이 만들도록 합니다.
fun createAndSubmitSendIt(title: String, message: String, transferred: (Long) -> Unit) {
val answer = TODO("whatever you need to do")
transferred(answer)
}
그런 다음 원하는 대로 사용하면 됩니다! 제 기억이 맞다면 kotlin/jvm 컴파일러가 하는 일은 인터페이스를 만드는 것과 같습니다.
도움이 되기를 바랍니다!
또 다른 해결책은 typealias를 선언하고 어딘가에 주입하고 호출하는 것입니다. 여기 예:
internal typealias WhateverListener = (String) -> Unit
그런 다음 해당 typealias를 클래스에 주입합니다.
class Gallery constructor(private val whateverListener: WhateverListener) {
...
galleryItemClickListener.invoke("hello")
...
}
그래서 우리는 람다가 있습니다:
val gallery = Gallery { appNavigator.openVideoPlayer(it) }
솔루션을 찾는 동안 트릭을 보여준 동료 Joel Pedraza에게 감사를 표합니다. <3.
Kotlin과 Java 모두에서 최상의 액세스 경험을 목표로 하는 경우 이 문제에 대한 단일 궁극적인 솔루션은 없습니다.
Kotlin 개발자가 Kotlin 인터페이스에 대한 SAM 변환이 불필요하다고 생각하지 않았다면 "Kotlin Interface" 방법이 궁극적인 솔루션이 될 것입니다.
https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
또한 이 기능은 Java interop에서만 작동합니다. Kotlin에는 적절한 함수 유형이 있으므로 함수를 Kotlin 인터페이스 구현으로 자동 변환할 필요가 없으므로 지원되지 않습니다.
사용 사례에 가장 적합한 솔루션을 선택하십시오.
코틀린 함수 유형
- 코틀린 API: 완벽
- Kotlin 액세스: 완벽
- 자바 액세스:
- Function1과 같은 자동 생성 매개변수 유형(Java 8 람다의 경우 큰 문제가 아님)
return Unit.INSTANCE;
무효 반환 대신 자세한 정보를 제공 합니다.
class KotlinApi {
fun demo(listener: (response: String) -> Unit) {
listener("response")
}
}
fun kotlinConsumer() {
KotlinApi().demo { success ->
println(success)
}
}
public void javaConsumer() {
new KotlinApi().demo(s -> {
System.out.println(s);
return Unit.INSTANCE;
});
}
코틀린 인터페이스
- Kotlin API: 추가 인터페이스 정의.
- Kotlin 액세스: 너무 장황함
- 자바 액세스: 완벽
class KotlinApi {
interface Listener {
fun onResponse(response: String)
}
fun demo(listener: Listener) {
listener.onResponse("response")
}
}
fun kotlinConsumer() {
KotlinApi().demo(object : KotlinApi.Listener {
override fun onResponse(response: String) {
println(response)
}
})
}
//If Kotlin had supported SAM conversion for Kotlin interfaces. :(
//fun kotlinConsumer() {
// KotlinApi().demo {
// println(it)
// }
//}
public void javaConsumer() {
new KotlinApi().demo(s -> {
System.out.println(s);
});
}
자바 인터페이스
- Kotlin API: 혼합 Java 코드.
- Kotlin 액세스: 약간 장황함
- 자바 액세스: 완벽
class KotlinApi {
fun demo(listener: Listener) {
listener.onResponse("response")
}
}
public interface Listener {
void onResponse(String response);
}
//Semi SAM conversion
fun kotlinConsumer() {
KotlinApi().demo(Listener {
println(it)
})
}
public void javaConsumer() {
new KotlinApi().demo(s -> {
System.out.println(s);
});
}
여러 방법
- Kotlin API: 다중 메소드 구현
- Kotlin Access: 올바른 방법을 사용하면 완벽합니다. 자동 완성은 장황한 방법도 제안합니다.
- 자바 액세스: 완벽합니다. 자동 완성은
JvmSynthetic
주석으로 인해 함수 유형 방법을 제안하지 않습니다.
class KotlinApi {
interface Listener {
fun onResponse(response: String)
}
fun demo(listener: Listener) {
demo {
listener.onResponse(it)
}
}
@JvmSynthetic //Prevents JVM to use this method
fun demo(listener: (String) -> Unit) {
listener("response")
}
}
fun kotlinConsumer() {
KotlinApi().demo {
println(it)
}
}
public void javaConsumer() {
new KotlinApi().demo(s -> {
System.out.println(s);
});
}
자바 API
- Kotlin API: Kotlin API는 없으며 모든 API 코드는 Java입니다.
- Kotlin 액세스: 완벽
- 자바 액세스: 완벽
public class JavaApi {
public void demo(Listener listener) {
listener.onResponse("response");
}
public interface Listener {
void onResponse(String response);
}
}
//Full SAM conversion
fun kotlinConsumer() {
JavaApi().demo {
println(it)
}
}
public void javaConsumer() {
new JavaApi().demo(s -> {
System.out.println(s);
});
}
ReferenceURL : https://stackoverflow.com/questions/43469241/passing-lambda-instead-of-interface
'IT이야기' 카테고리의 다른 글
반응 수명 주기 방법 이해 (0) | 2021.10.25 |
---|---|
Tensorflow는 레이블이 있는 이미지를 읽습니다. (0) | 2021.10.25 |
ASP.NET MVC의 컨트롤러에서 경로 이름 얻는 방법 (0) | 2021.10.24 |
Eclipse에서 XML 파일 실행을 중지하는 방법 (0) | 2021.10.24 |
name()과 local-name()의 차이점 (0) | 2021.10.24 |