seqs 和 iterator-seq 之间的关系如下:一个 iterator-seq 从一个迭代器创建一个 seq。
原谅这里的冗长,但要回答“如何迭代 iterator-seq 的输出”的问题,我们必须首先明确定义为什么需要调用 iterator-seq 以开头:
在 Clojure 中,您不会发现自己需要太频繁地创建 iterator-seq 对象。由于 clojure 可以非常轻松地处理“Iterable”java 对象的迭代(参见:http ://clojuredocs.org/clojure_core/clojure.core/iterator-seq )。但是,迭代器本身是不可迭代的。
要完全理解这一点,您需要了解 Iterables 和 Iterators 之间的区别,这主要是由于在 Java 世界中保持语义一致和直接:为什么 Java 的 Iterator 不是 Iterable?.
那么什么是'seq'?
在clojure 中有一个比java 的Iterator 接口更高的抽象,即ISeq。iterator-seq 在底层为我们创建了一个 ISeq。这个 ISeq 对象现在可以被许多 Clojure 函数使用,这些函数对项目的顺序列表进行操作。
user=> (iterator-seq (.iterator (new java.util.ArrayList ["A" "B"])))
("A" "B")
;Thus, we now have an ISeq implementation derived from an iterator.
因此,您的“iterator-seq”函数正在为您创建一个来自 java 迭代器的 Clojure“序列”。澄清一下——当我们在不可迭代的对象上调用“iterator-seq”时的错误信息是有用的:
user=> (iterator-seq "ASDF")
java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Iterator (NO_SOURCE_FILE:0)
这告诉我们“iterator-seq”函数需要一个 java.util.Iterator 作为输入。
您可能遇到的下一个合乎逻辑的问题是:
为什么我们需要从迭代器创建序列?seq 抽象与 java 中的迭代器抽象有何不同?
Iterable 接口不像 Clojure 的 ISeq 那样抽象。例如,考虑字符串。显然,字符串是顺序的。然而,它们在 Java 中不可迭代。数组也是如此。
从clojure网站:
“seq 适用于 Java 引用数组、Iterables 和字符串。由于该库的大部分其余部分都是基于这些函数构建的,因此对在 Clojure 算法中使用 Java 对象有很好的支持。”
因此,您的 iterator-seq 的目的是将您的迭代器对象“包装”成一个序列抽象,该抽象将能够利用所有 clojures 功能优势。
定义 iterator-seq 的作用
来自http://clojure.org/sequences:
“seq 函数产生了适合集合的 ISeq 实现。”
在您的情况下,我们可以这样说:
“iterator-seq 函数为您的 getIndexWordsIterator 生成 ISeq 的实现”。
最后:我怎样才能迭代一个 seq ?
这个问题需要根据上下文仔细回答。
迭代当然是可能的 - 但不是 clojure 的主要关注点,它可能不是你真正想要的。由于 iterator-seq 已经为我们创建了一个 SEQ,现在我们可能可以使用 Clojure 的函数运算符之一使用该 seq(即在列表推导、映射函数等中)。这消除了手动迭代的需要。
例如,我们经常遍历一个列表来查找一个值。在 clojure 中,我们可以使用 filter 函数找到一个值:
user=> (filter #(= \A %) (seq "ABCD"))
(\A)
而不是过滤,也许我们想通过迭代将一个函数应用于多个对象,将结果存储在一个新的集合中。同样,这不需要通过 Clojure 中的显式迭代来完成:
user=> (map #(.hashCode %) (seq "ABCZ"))
(65 66 67 90)
最后,如果您真的需要手动遍历您的集合,您可以使用 Loop-recur 构造手动尾递归遍历您的序列,一次一个元素: http: //clojure.org/functional_programming#Functional%20Programming --递归%20循环。或者您可以使用标准递归调用。