Передайте лямбду как метод расширения - PullRequest
0 голосов
/ 22 января 2020

Я сейчас изучаю kotlin и вступил в следующий сценарий. На Ktor сервере есть метод со следующей подписью:

fun Route.webSocket(protocol: String? = null, handler: suspend DefaultWebSocketServerSession.() -> Unit) {
    webSocketRaw(protocol) {
        proceedWebSocket(handler)
    }
}

, где я должен взаимодействовать с ним примерно так:

embeddedServer(Netty, 8080) {
        install(Routing) {
            webSocket("/ws") {
                // Handle websocket connection here
            }
        }
}

То есть websocket принимает labda, что это метод расширения DefaultWebSocketServerSession и имеет свой контекст. Я хотел бы преобразовать эту лямбду в обработчик, чтобы я мог передать ее откуда-то еще, я думаю, она должна выглядеть примерно так:

embeddedServer(Netty, 8080) {
        install(Routing) {
            webSocket("/ws", myHandler::handle)
        }
}

//...
fun suspend handle(context: DefaultWebSocketServerSession): Unit {
    // Handle websocket connection here
}

Итак, мой вопрос, как мне преобразовать suspend DefaultWebSocketServerSession.() -> Unit в (DefaultWebSocketServerSession) -> Unit, или как мне реализовать обработчик с подписью suspend DefaultWebSocketServerSession.() -> Unit, чтобы я мог передать его извне?

PS

Я знаю, что мог бы сделать это

embeddedServer(Netty, 8080) {
        install(Routing) {
            webSocket("/ws") {
                myHandler.handle(this)
            }
        }
}

Но это не изящно

1 Ответ

2 голосов
/ 22 января 2020

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

class A

class AHandler {
  fun handle(a: A) {
    println("AHandler $a")
  }
}

fun useLambdaWithReceiver(lambda: A.()->Unit) {
  val a = A()
  lambda(a)
}

fun useNormalLambda(lambda: (A)->Unit) {
  useLambdaWithReceiver(lambda)
}

fun main() {
  val handler = AHandler()
  useLambdaWithReceiver {
    println("useLambdaWithReceiver $this")
  }
  useNormalLambda {
    println("useNormalLambda $it")
  }
  useLambdaWithReceiver(handler::handle)
  useNormalLambda(handler::handle)
}

Вывод:

useLambdaWithReceiver A@174d20a
useNormalLambda A@3c756e4d
AHandler A@2ef5e5e3
AHandler A@6d00a15d

Все скомпилировано и преобразовано автоматически. Таким образом, вы можете просто передать свой метод-обработчик, и все будет хорошо, если только нет ошибки с модификатором suspend, о которой я не знаю.

...