将 lambda 作为扩展方法传递
Pass lambda as extension method
我最近在学习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
的扩展方法并且有它的上下文。我想将此 lambda 转换为处理程序,以便我可以从其他地方传递它,我想它应该看起来像这样:
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)
}
}
}
但这感觉并不优雅
不需要自己转换任何东西。 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
修饰符的错误。
我最近在学习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
的扩展方法并且有它的上下文。我想将此 lambda 转换为处理程序,以便我可以从其他地方传递它,我想它应该看起来像这样:
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)
}
}
}
但这感觉并不优雅
不需要自己转换任何东西。 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
修饰符的错误。