首页 > 解决方案 > Groovy 中是否有与 Python 的 yield 行为等价的行为?

问题描述

尝试学习 Groovy,到目前为止,这是一次有趣且略微令人困惑的冒险。我目前正在尝试做的是建立一个服务器,wget向它发出请求,当收到该请求时,执行某个操作 - 在这种情况下,只需创建一个新文件:

import java.net.http.HttpResponse

class ServerLogic {
    static def holdupServer() {
        println('Standing up server..\n')
        def socketServer = new ServerSocket(5000)
        // server is up
        socketServer.accept { socket ->
        // the lines below only execute when a connection is made to the server
        socket.withStreams { input, output ->
            println("[${new Date()}] HELLO\n")
            def newFile = new File("/home/nick/IdeaProjects/groovy_learning/resources/new.txt")
            newFile.createNewFile()
            newFile.text = 'Hello!!!'
            println("NEW FILE SHOULD HAVE BEEN CREATED.")
            println ">> READ: ${input.newReader().readLine()}"
        }
    }
        return HttpResponse
    }

}

ServerLogic.holdupServer()

使用上面的代码,当我执行 a 时wget http://localhost:5000,它“工作”,因为文件是按照我想要的方式创建的,但wget输出不满意:

--2021-07-17 15:42:32--  http://localhost:5000/
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:5000... connected.
HTTP request sent, awaiting response... No data received.
Retrying.

--2021-07-17 15:42:33--  (try: 2)  http://localhost:5000/
Connecting to localhost (localhost)|127.0.0.1|:5000... failed: Connection refused.
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:5000... failed: Connection refused.  
// these occur because the server has shut down after the last println call, when the `return HttpResponse` triggers

因此,我们可以推断出没有返回正确的响应,即使我有return HttpResponseaftersockerServer.accept ...逻辑。我对如何解决问题的想法(主要是因为我来自 Python 背景)将以某种方式模仿yieldPython 中的响应(基本上,在不中断holdupServer()逻辑并因此中断服务器连接的情况下返回响应)。有没有办法在 Groovy 中实现这一点,或者有没有一种不同的方法可以用来在HttpResponse不退出holdupServer()块的情况下基本上返回有效值?

标签: pythongroovy

解决方案


解释

您可以使用函数回调,它在 Groovy 中转换为闭包回调。基本上,您将要返回的值传递给另一个函数/方法,以延迟当前方法上的堆栈。这种方法基本上适用于所有语言。例如,在 java(不支持 lambda 的版本)中,您必须传递一个对象,稍后您将在该对象中调用一个方法。

例子

import java.net.http.HttpResponse

class ServerLogic {
    static def holdupServer(Closure closure) {
        (0..2).each {
            closure.call(HttpResponse)
        }
    }
}

ServerLogic.holdupServer { httpResponse ->
    println httpResponse
}

输出

interface java.net.http.HttpResponse
interface java.net.http.HttpResponse
interface java.net.http.HttpResponse

解决 OP 的评论

您必须提供一些标题。至少Content-Type并且Content-Length应该连同格式正确的数据和 HTTP 状态(在本例中为 HTTP/1.1 200)一起提供。此外,您应该将ServerSocket.accept调用包装在一个 while 循环中。

请参阅有关 HTTP 的 MDN概述

代码

class ServerLogic {
    static HEADERS = [
      "HTTP/1.1 200",
      "Content-Type: text/html; charset=utf-8",
      "Connection: Keep-Alive",
      "Keep-Alive: timeout=5, max=1000",
      "Content-Length: %d\r\n",
      "%s"
    ].join("\r\n")

    static def holdupServer(Closure callback) {
      println('Standing up server..\n')
      def socketServer = new ServerSocket(5000)
        // server is up
      while(true) { // Continue to accept connections
        socketServer.accept { socket ->
        // the lines below only execute when a connection is made to the server
          callback.call(socket) // call function
      }
    }
  }
}

ServerLogic.holdupServer { Socket socket ->
  String data = "RESPONSE <--\n"
  def response = String.format(ServerLogic.HEADERS, data.size(), data)
  println response
  socket << response
}

客户端输出

RESPONSE <--

推荐阅读