Clojure 编程语言:充分利用 Eclipse 的 Clojure 插件(4)

通过上述这两个简单的例子,我们已经看到了 Clojure 的很多特性。Clojure 的另一个重要的方面是其与 Java 语言的紧密集成。让我们看另外一个例子来了解从 Clojure 使用 Java 是多么有帮助。

示例 3:使用 Java 技术

Java 平台能提供的功能很多。JVM 的性能以及丰富的核心 API 和以 Java 语言编写的第三方库都是功能强大的工具,能够帮助避免大量重复的工作。Clojure 正是围绕这些理念构建的。在 Clojure 中,很容易调用 Java 方法、创建 Java 对象、实现 Java 界面以及扩展 Java 类。为了举例说明,让我们来看看另一个 Project Euler 问题。

清单 10. Project Euler 的问题 8

Find the greatest product of five consecutive digits in the 1000-digit number. 73167176531330624919225119674426574742355349194934 96983520312774506326239578318016984801869478851843 85861560789112949495459501737958331952853208805511 12540698747158523863050715693290963295227443043557 66896648950445244523161731856403098711121722383113 62229893423380308135336276614282806444486645238749 30358907296290491560440772390713810515859307960866 70172427121883998797908792274921901699720888093776 65727333001053367881220235421809751254540594752243 52584907711670556013604839586446706324415722155397 53697817977846174064955149290862569321978468622482 83972241375657056057490261407972968652414535100474 82166370484403199890008895243450658541227588666881 16427171479924442928230863465674813919123162824586 17866458359124566529476545682848912883142607690042 24219022671055626321111109370544217506941658960408 07198403850962455444362981230987879927244284909188 84580156166097919133875499200524063689912560717606 05886116467109405077541002256983155200055935729725 71636269561882670428252483600823257530420752963450

在这个问题中,有一个 1,000-位的数字。在 Java 技术里,该数可以通过 BigInteger 表示。但是,我们无需在整个数上进行计算 — 只需每次计算 5 位。因而,将它视为字符串会更为简单。不过,为了进行计算,我们需要将这些数位视为整数。所幸的是,在 Java 语言中,已经有了一些 API,可用来在字符串和整数之间来回转换。作为开始,我们首先需要处理上面这一大段不规则的文本。

清单 11. 解析文本

(def big-num-str (str "73167176531330624919225119674426574742355349194934 96983520312774506326239578318016984801869478851843 85861560789112949495459501737958331952853208805511 12540698747158523863050715693290963295227443043557 66896648950445244523161731856403098711121722383113 62229893423380308135336276614282806444486645238749 30358907296290491560440772390713810515859307960866 70172427121883998797908792274921901699720888093776 65727333001053367881220235421809751254540594752243 52584907711670556013604839586446706324415722155397 53697817977846174064955149290862569321978468622482 83972241375657056057490261407972968652414535100474 82166370484403199890008895243450658541227588666881 16427171479924442928230863465674813919123162824586 17866458359124566529476545682848912883142607690042 24219022671055626321111109370544217506941658960408 07198403850962455444362981230987879927244284909188 84580156166097919133875499200524063689912560717606 05886116467109405077541002256983155200055935729725 71636269561882670428252483600823257530420752963450"))

这里,我们利用了 Clojure 对多行字符串的支持。我们使用了 str 函数来解析这个多行字符串。之后,使用 def 宏来定义一个常量,称为 big-num-str。不过,将其转换为一个整数序列将十分有用。这在清单 12 中完成。

清单 12. 创建一个数值序列

(def the-digits (map #(Integer. (str %)) (filter #(Character/isDigit %) (seq big-num-str))))

同样地,让我们从最里面的表达式开始。我们使用 seq 函数来将 big-num-str 转变为一个序列。不过,结果表明此序列并非我们所想要的。REPL 可以帮助我们看出这一点,如下所示。

清单 13. 查看这个 big-num-str 序列

user=> (seq big-num-str) (\7 \3 \1 \6 \7 \1 \7 \6 \5 \3 \1 \3 \3 \0 \6 \2 \4 \9 \1 \9 \2 \2 \5 \1 \1 \9 \6 \7 \4 \4 \2 \6 \5 \7 \4 \7 \4 \2 \3 \5 \5 \3 \4 \9 \1 \9 \4 \9 \3 \4 \newline...

REPL 将字符(一个 Java char)显示为 \c。因此 \7 就是 char 7,而 \newline 则为 char \n(一个换行)。这也是直接解析文本所得到的结果。显然,我们需要消除换行并转换为整数,然后才能进行有用的计算。这也正是我们在清单 11 中所做的。在那里,我们使用了一个过滤器来消除换行。请再次注意,我们为传递给 filter 函数的断言函数使用了一个简短的闭包。闭包使用的是 Character/isDigit。这是来自 java.lang.Character 的静态方法 isDigit。因此,这个过滤器只允许数值 char,而会丢弃换行字符。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/343500d1f46862334c243a65e4062571.html