【问题标题】:Clojure: java.lang.Integer cannot be cast to clojure.lang.IFnClojure:java.lang.Integer 不能转换为 clojure.lang.IFn
【发布时间】:2014-07-23 17:59:37
【问题描述】:

我知道这个标题有很多问题,但我无法从他们那里得到答案,所以就这样吧。

我是一位经验丰富的程序员,但对 Clojure 来说还很陌生。我正在尝试通过将 RTF 文件转换为 HTML 文件然后调用 html 解析器来解析它。

我使用的转换器 (unrtf) 总是打印到标准输出,所以我需要捕获输出并自己编写文件。

(定义解析-rtf “使用 unrtf 解析 rtf 文件” [#^java.io.InputStream istream 字符集] (让 [rtffile (File/createTempFile "parse" ".rtf" (File."/vault/tmp/")) htmlfile (File/createTempFile "parse" ".ohtml" (File. "/vault/tmp/")) 命令(str“/usr/bin/unrtf” (.getPath rtffile) ) ] (尝试 (with-open [rtfout(FileOutputStream.rtffile)] (IOUtils/复制 istream rtfout)) (let [ proc (.exec (Runtime/getRuntime) 命令) ostream (.getInputStream 过程) 结果(.waitFor proc)] (如果(> 结果 0) ( (println "unrtf failed" 命令结果) ;抛出异常会导致记录解析失败 (throw (Exception. (str "RTF to HTML conversion failed"))) ) ( (with-open [htmlout (FileOutputStream.htmlfile)] (IOUtils/copy ostream htmlout)) ;因为我们现在有了 html,所以通过 html 解析器运行它 (parse-html (FileInputStream.htmlfile) 字符集) ) ) ) (最后 (.删除 rtf 文件) (.delete html文件) ) )))

异常指向带有

的行
(IOUtils/copy ostream htmlout))

这真的让我很困惑,因为我之前使用过这种形式(就在尝试之后:),而且那里似乎还可以。我看不出有什么区别。

感谢您提供的任何帮助。

【问题讨论】:

  • 您错误地使用了括号。特别是您的 if 语句是错误的。括号不是花括号。当您有一个额外的对时,您将内部表达式作为函数调用。你想要(if condition something something-else),你有(if condition (something) (something-else))

标签: clojure


【解决方案1】:

正如其他人正确指出的那样,您不能只为代码组织添加额外的括号来将表单组合在一起。 Clojure 文件中的括号是在相应代码中分隔列表的标记;列表作为 s 表达式求值 - 也就是说,第一种形式被求值,结果作为函数调用(除非它命名为特殊形式,例如 iflet)。

在这种情况下,您有以下内容:

(
  (with-open [htmlout  (FileOutputStream. htmlfile)]
    (IOUtils/copy ostream htmlout))
  ; since we now have html, run it through the html parser
  (parse-html (FileInputStream. htmlfile) charset)
)

IOUtils/copy 函数有一个整数返回值(复制的字节数)。然后在评估周围的with-open 宏时返回此值。由于with-open 表单是列表中的第一个表单,因此Clojure 将尝试将IOUtils/copy 的整数返回值作为函数调用,从而导致您看到的异常。

要评估多个表单的副作用而不调用第一个表单的结果,请将它们包装在do 表单中;这是一种特殊形式,它计算每个表达式并返回最终表达式的结果,丢弃所有其他表达式的结果。许多核心宏和特殊形式,例如 letwhenwith-open(以及许多其他)接受多个表达式并在隐式 do 中计算它们。

【讨论】:

  • 我对允许多个语句的 let 和 function 形式感到困惑。回过头来重新阅读我的一些资料,我发现这些是例外而不是规则。
  • 即使在函数或 let 表单中,如果您像在此代码中那样使用额外的一对括号,您也会得到相同的错误。
【解决方案2】:

我没有尝试运行你的代码,只是看了一下,在if (> result 0) 之后你有((println ...)(throw ...)) 没有do。有一个额外的括号会导致来自内部括号的返回值被视为一个函数并被执行。

尝试包含它,像这样(do (println ...) (throw ...))

【讨论】:

    猜你喜欢
    • 2023-04-07
    • 2017-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多