doto并有条件地设置属性

时间:2010-09-14 22:12:42

标签: clojure

我想写:

(defn download-web-page
    "Downloads the webpage at the given url and returns its contents."
    [^String url ^String user ^String password]
    (with-open [client (doto (WebClient.)
                       (when user (.set_Credentials (NetworkCredential. user password ""))))]
    (.DownloadString client url)))

所以我只想在将它们作为函数的参数给出时设置凭据。然而,它似乎没有那样工作 - 当我用if替换when时也没有。

如果我完全删除时,该功能正常。

我想我不能在doto中使用 - 有没有很好的方法来写这个?

4 个答案:

答案 0 :(得分:4)

(注意:这应该都有效,但我现在无法测试。请给它自己的理智检查。)

你可以写

(defn download-web-page
  "Downloads the webpage at the given url and returns its contents."
  ([^String url] (download-web-page url nil nil))
  ([^String url ^String user ^String password]
     (with-open [client (doto (WebClient.)
                          (-> (.set_Credentials
                               (NetworkCredential. user password ""))
                              (->> (when user))))]
       (.DownloadString client url))))
但是,这对我来说似乎很复杂。另一种方法:

(defn download-web-page
  "Downloads the webpage at the given url and returns its contents."
  ([^String url] (download-web-page url nil nil))
  ([^String url ^String user ^String password]
    (with-open [client (let [c (WebClient.)]
                         (when user
                           (.set_Credentials
                            (NetworkCredential. user password "")))
                         c)]
      (.DownloadString client url))))

第一个版本的复杂-> / ->>模式可以用宏抽象掉:

(defmacro doto-guard [guard action]
  `(-> ~action ~guard))

然后你可以写

(doto (WebClient.)
  (doto-guard (when user) (.setCredentials ...)))

这有一个很好的属性,你可以在一个doto形式中多次使用它,同时混合常规doto子句。好吧,如果你的代码更频繁地出现这种事情,那就太好了。否则基于let的版本应该可以。

(如果这个模式经常出现 ,那么宏可以变得更加灵活......它也很容易让它变得更加更少灵活,但更漂亮例如,将~guard替换为(when ~guard),以便在使用时可以写(doto-guard user (.setCredentials ...))。但是,选择特定版本的任何深层原因都必须来自更广泛的背景。 )

分成两个函数体只是一种风格问题 - 当没有实际提供凭证时,我宁愿不写nil nil

答案 1 :(得分:3)

我只想把它写成:

(defn download-web-page
  "Downloads the webpage at the given url and returns its contents."
  [^String url ^String user ^String password]
  (with-open [client (WebClient.)]
    (when user
      (.set_Credentials client (NetworkCredential. user password "")))
    (.DownloadString client url)))

with-openclient没有任何特殊要求,只是它有一个无参数close方法,所以你不需要在任何意义上“完成”它在绑定向量中。

答案 2 :(得分:2)

(defn download-web-page
  "Downloads the webpage at the given url and returns its contents."
  [^String url ^String user ^String password]
  (let [client (WebClient.)]
    (when user 
      (.set_Credentials client (NetworkCredential. user password "")))
    (with-open [client client]
      (.DownloadString client url)))

(with-open [client client]...看起来有点奇怪,但是嘿,这是一个讨厌的有状态代码。如果doto中的条件设置足够频繁,可能保证宏,但我会首先跳转到构建器函数:

(defn build-web-client
  [^String user ^String password]
  (let [client (WebClient.)]
    (when user 
      (.set_Credentials client (NetworkCredential. user password "")))
    client))

(defn download-web-page
  "Downloads the webpage at the given url and returns its contents."
  [^String url ^String user ^String password]
    (with-open [client (build-web-client user password)]
      (.DownloadString client url)))

答案 3 :(得分:0)

您可以像这样将Descendants("table").LastOrDefault()嵌套在cond->内:

doto

哪个给您有条件的doto。