2010-09-14 79 views
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 (doto (WebClient.) 
         (when user (.set_Credentials (NetworkCredential. user password ""))))] 
    (.DownloadString client url))) 

所以我想只設置憑據時給他們作爲參數傳遞給函數。然而,它似乎並沒有這樣工作 - 當我用if替換時,它也不是。

該功能正常工作,如果我完全刪除時。

我想我不能在一個doto中使用一個 - 有沒有很好的方法來寫這個?

回答

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-open沒有對任何client特殊的要求,但它有一個無參數close方法,所以你並不需要「完成」它在任何意義上在綁定向量中。

+1

我從它被寫在需要的憑據設置的方式承擔連接打開之前。您的代碼首先打開,然後設置憑據。我不知道這是否有問題。 – 2010-09-14 23:47:04

+1

不,打開沒有打開任何東西。它*僅*保證當控制流離開with-open形式時,綁定變量是(.close)d,無論是通過異常還是正常返回。 – dreish 2010-09-15 17:50:53

+1

是的,你說得對。我的錯。 – 2010-09-15 18:04:11

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的版本應該沒問題。

(如果這種模式往往出現真的你,宏可以更加靈活......它也很誘人,使其略少靈活,但是更漂亮,用(when ~guard)更換~guard說,等在使用時,人們會寫(doto-guard user (.setCredentials ...))。但是,選擇特定版本的任何深層原因必須來自更廣泛的背景,但是)。

分成兩個函數體只是一個風格問題 - 我更喜歡當沒有提供憑證時,不要編寫nil nil

+0

這回答了Kurt的字面問題,但他問的是錯誤的問題。較簡單的代碼可以完成同樣的事情。 – dreish 2010-09-15 17:55:37

+0

儘管我有點厭惡「錯誤的問題」,但是絕望是正確的。 +1用於暗示沒有用戶和密碼的過載。 – 2010-09-15 20:04:59

+0

對不起,我不是故意要冒犯你們任何一個人。我一直在問錯誤的問題。我很確定每個人都這樣做。 – dreish 2010-09-15 20:37:25

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)))