Collections 集合上的高阶函数是否保证按顺序执行?

Collections 集合上的高阶函数是否保证按顺序执行?,collections,groovy,higher-order-functions,Collections,Groovy,Higher Order Functions,在另一个问题中,一位用户建议编写如下代码: def list = ['a', 'b', 'c', 'd'] def i = 0; assert list.collect { [i++] } == [0, 1, 2, 3] 在其他语言中,这样的代码被认为是不好的做法,因为collect的内容改变了其上下文的状态(这里它改变了i的值)。换句话说,关闭有副作用 这样的高阶函数应该能够并行运行闭包,并将其重新组装到新列表中。如果闭包中的处理是长时间的CPU密集型操作,那么在单独的线程中执行它们可能是

在另一个问题中,一位用户建议编写如下代码:

def list = ['a', 'b', 'c', 'd']
def i = 0; 
assert list.collect { [i++] } == [0, 1, 2, 3]
在其他语言中,这样的代码被认为是不好的做法,因为collect的内容改变了其上下文的状态(这里它改变了
i
的值)。换句话说,关闭有副作用

这样的高阶函数应该能够并行运行闭包,并将其重新组装到新列表中。如果闭包中的处理是长时间的CPU密集型操作,那么在单独的线程中执行它们可能是值得的。更改
collect
以使用来实现这一点很容易,但它会破坏上述代码

问题的另一个例子是,如果出于某种原因,
collect
以相反的顺序浏览集合,那么结果将是
[3,2,1,0]
。请注意,在这种情况下,列表尚未还原,0实际上是对“d”应用闭包的结果

有趣的是,这些函数在中以“迭代此集合”的形式记录,这表明迭代是顺序的


groovy规范是否明确定义了高阶函数的执行顺序,如
collect
each
?上面的代码是错误的还是正常的?

我不喜欢在闭包中依赖显式外部变量,原因是您在上面给出的

事实上,我定义的变量越少,我就越快乐;-)

对于可能并行的事情,总是编写代码,以期在单个线程无法处理的情况下使用某种级别的代码来包装它。为此,正如您所说,您希望尽可能少的可变性,并尝试完全避免副作用(如上面的外部计数器模式)

至于问题本身,如果我们以
collect
作为一个示例函数,并进行检查,我们可以看到给定的
对象
(以类似的方式完成,但对迭代器的引用方式略有不同)它沿着
InvokerHelper.asIterator(self)
进行迭代,将每个闭包调用的结果添加到结果列表中

InvokerHelper.asIterator
(再次)基本上是对传入的对象调用
iterator()
方法

因此,对于etc,它将按照迭代器定义的顺序遍历对象

因此,可以按照设计编写自己的类(由于duck类型,不需要实现
Iterable
),并定义如何迭代集合


我想通过询问Groovy规范,这个答案可能不是您想要的,但我认为没有答案。Groovy从来没有真正的“完整”规范(实际上这就是Groovy的要点)。

我认为保持传递的函数
collect
findAll
没有副作用通常是个好主意,不仅是为了保持低复杂度,而且为了在将来需要并行执行时使代码更加并行友好

但是在
each
的情况下,保持函数没有副作用没有多大意义,因为它不会做任何事情(事实上,这种方法的唯一目的是将act替换为for each循环的a)。有一些使用需要定义执行顺序的
每个
(及其变体,
eachWithIndex
reverseEach
)的示例

现在,从实用的角度来看,我认为有时在
collect
等方法中使用带有一些副作用的函数是可以的。例如,要转换
[索引,值]
中的列表,请对
和范围进行转置

但是一个
收集
和一个计数器也会起作用,我认为结果是最可读的:

def n = 0, enumerated = list.collect{ [n++, it] }

现在,如果Groovy提供了一个带有索引值param函数的
collect
和类似方法(请参阅),那么这个示例就没有意义了,但它有点表明,有时候我的答案是:)

更新了我的答案,添加了指向
集合之间的差异的链接,
列表
,和恰好有一个迭代器()方法的对象您是否发布了源代码的链接,希望人们在作者标签中注意到您的名字?没有人喜欢炫耀(不过对我有影响)。谢谢,我想我不能期待更好的答案。@Antoine你可以试试groovy用户邮件list@Don呵呵..虽然在作者名单上排名很靠后;-)
def enumerated = list.inject([]) { acc, val -> acc << [acc.size(), val] }
def n = 0, enumerated = list.collect{ [n++, it] }