【问题标题】:How to pass in a parameter to a static method in Clojure?如何将参数传递给 Clojure 中的静态方法?
【发布时间】:2018-01-21 13:03:45
【问题描述】:

我有以下方法:

package com.streambright.http.handlers;

import org.rapidoid.http.Req;
import org.rapidoid.u.U;

import java.util.Map;

public class EchoHandler {

    public static Map<String, String> handleEcho(Req req) {
        return U.map(req.headers());
    }
}

当我使用它时,它完全没问题:

On.get("/echo").managed(false).json(EchoHandler::handleEcho);

但是,当我尝试在 Clojure 中执行相同操作时,它会因参数数量错误而失败。

处理程序:

(ns s.echo-http-handler
  (:import
    [org.rapidoid.http  Req ]
    [org.rapidoid.u     U   ] )
  (:gen-class
    :methods [^:static [handler [org.rapidoid.http.Req] java.util.Map]]))

(defn -handler
  [Req req]
  (U/map (.headers req)))

当我启动服务器时:

(ns s.http
  (:require
    [s.echo-http-handler  :as echo    ] )
  (:import
    [org.rapidoid.config  Conf  ]
    [org.rapidoid.setup   On    ] ) )

    (defn start
      []
      (set-http-params!)
      (.json (.managed (On/get "/echo") false) echo/-handler))

它启动并抛出以下错误:

clojure.lang.ArityException: Wrong number of args (0) passed to: echo-http-handler/-handler

如何将 req 传递给 Clojure 中的函数?

【问题讨论】:

  • 您确定这是 Clojure 问题吗?我不熟悉 Rapidoid,但似乎 it 没有传递所需的参数。是什么决定了json 方法是否将参数传递给给它的函数?从快速搜索来看,似乎它可以同时接受 0 和 1 arity 函数。
  • 这归结为能够将 (Req req, Resp resp) -> {return ....} 代码从 Java 移植到 Clojure。我不知道该怎么做。
  • 但是,又是什么决定了给 'json` 的回调的数量?是库传递了错误数量的参数。
  • 为了使用 Clojure 中的函数式接口,您可以使用reify 创建一个实现该接口的对象。不幸的是,你不能使用简洁的匿名函数语法。

标签: java clojure rapidoid


【解决方案1】:

我曾经玩过一点rapidoid。您的错误是您试图仅将 Clojure 函数作为处理程序传递。相反,它应该是ReqHandler Java 类的实例。所以你需要创建一个匿名类的实例来扩展它。

错误:

(defn -handler
  [Req req]
  (U/map (.headers req)))

正确:

(reify ReqHandler
 (execute [this, ^Req req]
   ;; here, access req's fields to write the body or headers
   ))

【讨论】:

    【解决方案2】:

    假设问题在于它如何处理 Clojure 函数,以下应该可以工作:

    (ns your-namespace
      (:import [org.rapidoid.http Req ReqHandler]))
    
    ; Helper to create an object that implements ReqHandler
    (defn makeReqHandler [f]
      ; Basically "new ReqHandler {...}"
      (reify ReqHandler
        (execute [this, ^Req req] (f req))
    

    这个函数接受一个 Clojure 函数,并使用它来创建一个实现 ReqHandler 的对象。我认为问题在于假设(出于某种原因)您想要 .json 的 0-arity 重载,而您确实想要将参数传递给回调的重载。这个助手应该防止这种混淆。

    然后用作:

    (let [handler (makeReqHandler echo/-handler)]
      (.json (.managed (On/get "/echo") false) handler)))
    

    虽然也可以写成:

    (->  (On/get "/echo")
         (.managed false)
         (.json handler))
    

    甚至内联处理程序以表明仍然可以使用包装函数来使用简洁的匿名函数语法:

    (->  (On/get "/echo")
         (.managed false)
         (.json (makeReqHandler #(U/map (.headers %)))))
    

    这可以说更具可读性。因为在使用 Java 互操作时,this 总是隐含的第一个参数,doto-&gt; 非常适合摆脱嵌套。

    【讨论】:

    • 接近了! :) error = java.lang.AbstractMethodError: s.http_handlers$create_request_handler$reify__49.execute(Ljava/lang/Object;)Ljava/lang/Object;
    • @Istvan 您是否有可能导入了错误的 ReqHandler? ReqHandler 是一个接口,所以它不应该与抽象方法有任何关系。我将使用导入更新代码。
    • @Istvan 我将在使用完整计算机时更新导入。您一定导入了错误的文件。不涉及抽象类,因此错误没有意义。
    • @Istvan 您使用的是最新版本的库吗?如果他们从使用抽象类切换到接口,而您仍在使用使用抽象类的版本,则会因该错误而失败。尝试更新库并再次运行它。
    • 我使用的是最新版本。
    猜你喜欢
    • 2011-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-15
    • 2016-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多