在Scala中,未来可能会失败,这可以异步发现:
f onComplete {
case Success(_) => println("Great!")
case Failure(t) => println("An error has occurred: " + t.getMessage)
}
你怎么把它翻译成Clojure?我的阅读让我相信Clojure未来/承诺模型不像Scala那样强大,你不能像这样抓住失败。那又怎么办呢?
Scala的未来永远不需要被问及它的价值 - 当它很好并且准备就绪时它会告诉你发生了什么(包括它是否失败 - 这就是这个问题的症结所在)。这就是我所说的'异步'。 Scala未来可能处于三种可能状态之一 - 未完成,完成失败,成功完成。
Scala中一个典型的用例示例是一个返回Future [T]的远程调用,其中T是您真正想要获取的类型。如果远程JVM关闭,那么在超时后将发生case Failure(t)
。
这是一个非常直接的模型。在问题中我要求一个简单的替代方案。作为一个侧面评论,很高兴听到Clojure打算在某个时候采用Scala Futures模型。
答案 0 :(得分:1)
我记得Scala中的未来是monad所以搜索algo.monads
和fluokitten
以寻找合适的东西。最后我找到了Lenardo Borges' imminent
库。我认为这就是你想要的。
使用此命名空间声明
(ns imminent-proof.core
(:require [imminent.core :as i]
[clojure.core.match :refer [match]])
(:import [imminent.result Success Failure]))
这是失败案例
(-> (i/future (/ 1 0))
(i/on-complete #(match [%]
[{Success v}] (prn "success: " v)
[{Failure e}] (prn "failure: " e))))
这是成功案例
(-> (i/future (Thread/sleep 1000) 42)
(i/on-complete #(match [%]
[{Success v}] (prn "success: " v)
[{Failure e}] (prn "failure: " e))))
这是超时案例
(-> (i/future (Thread/sleep 1000) 42)
(i/await 500)
(i/on-complete #(match [%]
[{Success v}] (prn "success: " v)
[{Failure e}] (prn "failure: " e))))
答案 1 :(得分:0)
我想知道Clojure是否需要特定的构造来处理失败期货的这种情况。以下行给了我相同的功能:
(defn f-cond[f func-ok func-fail]
(future (try (func-ok @f) (catch Exception e (func-fail e)))))
然后:
@(f-cond (future (throw (Exception. "hi")))
identity #(println "Failed: " (.getCause %)))
结果
Failed: #<Exception java.lang.Exception: hi>
答案 2 :(得分:0)
未来的宏只是包装Java Future,而deref reader宏只是在未来调用.get()
时的语法糖:
user=> (source future)
(defmacro future
"Takes a body of expressions and yields a future object that will
invoke the body in another thread, and will cache the result and
return it on all subsequent calls to deref/@. If the computation has
not yet finished, calls to deref/@ will block, unless the variant of
deref with timeout is used. See also - realized?."
{:added "1.1"}
[& body] `(future-call (^{:once true} fn* [] ~@body)))
nil
user=> (source future-call)
(defn future-call
"Takes a function of no args and yields a future object that will
invoke the function in another thread, and will cache the result and
return it on all subsequent calls to deref/@. If the computation has
not yet finished, calls to deref/@ will block, unless the variant
of deref with timeout is used. See also - realized?."
{:added "1.1"
:static true}
[f]
(let [f (binding-conveyor-fn f)
fut (.submit clojure.lang.Agent/soloExecutor ^Callable f)]
(reify
clojure.lang.IDeref
(deref [] (deref-future fut))
clojure.lang.IBlockingDeref
(deref
[ timeout-ms timeout-val]
(deref-future fut timeout-ms timeout-val))
clojure.lang.IPending
(isRealized [] (.isDone fut))
java.util.concurrent.Future
(get [] (.get fut))
(get [_ timeout unit] (.get fut timeout unit))
(isCancelled [] (.isCancelled fut))
(isDone [] (.isDone fut))
(cancel [_ interrupt?] (.cancel fut interrupt?)))))
nil
user=>
因此,测试失败与java没有什么不同:你捕获ExecutionException
,请参阅java doc for Future:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#get()
因此解决方案是从deref
中捕获异常,如其他答案中所示。