在 clojure 中指定对象的 class

Specifying class of object in clojure

我不想抓取需要登录的网站。我决定使用 Jsoup 来做到这一点。我遇到了问题 "translating" 这行代码正确地转换为 Clojure:

Connection.Response loginForm = Jsoup.connect("**url**")
        .method(Connection.Method.GET)
        .execute();

没有在我的 Clojure 代码中指定 class Connection.Response,连接有 class jsoup.helper.HttpConnect,它缺少我需要从会话中获取 cookie 的方法。

到目前为止,我已经想出了以下 Clojure 代码:

(import (org.jsoup Jsoup Connection
               Connection$Response Connection$Method))
(do
 (def url "*URL*")
 (def res (doto (org.jsoup.Jsoup/connect url)
   (.data "username" "*USERNAME*")
   (.data "password" "*PASSWORD")
   (.method Connection$Method/POST)
   (.execute)))
 (type res))

问题是您正在使用 doto,而您应该使用 -> 线程宏:

(let [url "*URL*"]
  (-> url
      (org.jsoup.Jsoup/connect)
      (.data "username" "*USERNAME*")
      (.data "password" "*PASSWORD*")
      (.method "Connection$Method/POST)
      (.execute)))

doto 形式通常在您需要设置一个 Java 对象时使用,该对象提供 setter 类方法 returning void 并防止你从使用线程。

(doto (SomeClass.)
  (.setA 1)
  (.setB 2)
  (.execute))

转换为:

(let [obj (SomeClass.)]
  (.setA obj 1)
  (.setB obj 2)
  (.execute obj)
  obj)

如您所见,doto 不是 return 最后一个方法调用的结果,而是作为其第一个参数提供的对象(在本例中为 SomeClass 对象)。因此,您当前的代码 return 是由 Jsoup/connect 方法创建的对象(如您所见,jsoup.helper.HttpConnect)而不是 execute() 方法调用的 Connection.Response 结果。

您需要的是:

(-> (SomeClass.)
    (.withA 1)
    (.withB 2)
    (.execute))

其中 with* 是构建器方法 returning this 而不是 void.

以上线程形式等价于:

(.execute
  (.withB
    (.withA
      (SomeClass.)
      1)
    2))