问题中的代码可以按照这样的习惯性方式重新编写(以任何打字错误为模——这里希望没有):
(defn download-web-page
"Downloads the webpage at the given url and returns its contents."
[^String url ^String user ^String password]
(let [req (doto (HttpWebRequest/Create url)
(.set_Credentials (NetworkCredential. user password ""))
(.set_UserAgent ".NET"))
response (.GetResponse req)
response-stream (.GetResponseStream res)
rdr (StreamReader. response-stream)
content (.ReadToEnd rdr)]
(.Close rdr)
(.Close response-stream)
(.Close response)
content))
with-open
电话
.Close
.readToEnd
急切地消耗整个流,这可以进一步简化为
更新:
打开
.Dispose
在绑定对象上。如果这可以代替
,很好;如果
.关闭
是必需的,您可以编写自己的版本
打开
使用
.关闭
而不是(可能复制
the original
):
(defn download-web-page
"Downloads the webpage at the given url and returns its contents."
[^String url ^String user ^String password]
(let [req (doto (HttpWebRequest/Create url)
(.set_Credentials (NetworkCredential. user password ""))
(.set_UserAgent ".NET"))]
(with-open [response (.GetResponse req)
response-stream (.GetResponseStream res)
rdr (StreamReader. response-stream)]
(.ReadToEnd rdr))))
一些评论:
-
不要使用
def
defn
除非你真的知道你需要这样做。(实际上是在顶层中立即使用它们
let
如果需要创建的对象关闭
让
-绑定本地人。。。有什么比这更奇怪的吗
仔细检查!)
定义
&Co.创建顶级变量或重置其根绑定;在程序的常规操作过程中这样做完全违背Clojure的功能精神。也许更重要的是,从一个实际的角度来看,任何依赖于“拥有”一堆变量的函数一次只能由一个线程执行;这是没有理由的
download-web-page
因此应该受到限制。
-
让
-引入的绑定可能不是相互递归的;后面的绑定可能引用前面的绑定,但不是相反。相互递归的局部函数可以用
letfn
很好用。