【问题标题】:How should I have figured out that Groovy's each() does not change the list's elements?我怎么知道 Groovy 的 each() 不会改变列表的元素?
【发布时间】:2013-05-02 13:00:00
【问题描述】:

示例

此测试失败,因为each 没有修改列表的元素。

void test_each_DoesNotModifyListElements() {
    List<String> list = ["a", "b", "c"]
    list.each { it =  it + "z" }
    assert ["az", "bz", "cz"] == list
}

这个测试通过了,因为collect 返回了一个包含修改过的元素的新列表。

void test_collect_ReturnsNewListWithModifiedElements() {
    List<String> list = ["a", "b", "c"]
    list = list.collect{ it + "z" }
    assert ["az", "bz", "cz"] == list
}

假设

此时,我假设 each 不会修改列表的元素,因为我已经编写了下面的测试,并且我假设这就是测试告诉我的。如果我错了,请纠正我。

void test_each_DoesNotModifyListElements1() {
    List<String> list = ["a", "b", "c"]
    list.each { it + "z" }
    assert ["az", "bz", "cz"] == list
}

void test_each_DoesNotModifyListElements2() {
    List<String> list = ["a", "b", "c"]
    list.each { it =  it + "z" }
    assert ["az", "bz", "cz"] == list
}

void test_each_DoesNotModifyListElements3() {
    List<String> list = ["a", "b", "c"]
    list = list.each { it =  it + "z" }
    assert ["az", "bz", "cz"] == list
}

问题

所以问题是:作为一个 Groovy 初学者,我应该如何事先知道,即在编写测试和googling 之前,each 不会更改列表的元素?

通过阅读文档?

Groovy each documentation:遍历聚合类型或数据结构,传递每个 项目到给定的闭包。自定义类型可以通过以下方式使用此方法 只需提供一个“iterator()”方法。退回的物品 生成的迭代器将被传递给闭包。

通常,我最终会花费大量时间尝试各种事情并在谷歌上搜索答案。不应该有更有效的方法吗?有吗?

【问题讨论】:

  • 您是否希望 for 循环能够在 Java 中更改 List 的元素?
  • @tim_yates:我想说...是吗?你是这个意思吗? void test_for_loop() { List&lt;String&gt; list = ["a", "b", "c"] for (int i = 0; i &lt; list.size(); i++) { list[i] = list[i] + "z" } assert ["az", "bz", "cz"] == list }
  • 啊,但是你在循环中改变了list,在你上面的each例子中,你没有提到list本身
  • 如果你想要list = [ 'a', 'b', 'c' ] ; list.eachWithIndex { it, idx -&gt; list[ idx ] = it + 'z' },你也可以使用each,但使用collect会更好
  • 相同的值,但与each 中的语义不同,该值已作为参数传递到each 闭包中,因此任何更改都将丢失(与Java 中的任何方法调用一样) .使用 for 循环,您正在修改位置 [0] 的列表的实际内容。

标签: groovy


【解决方案1】:

嗯,这离 Java/Groovy 编程基础不远了。有对象,也有变量。变量可以保存到对象的“链接”,称为引用。所以基本上,使用变量你可以访问存储在计算机内存深处的真实对象。

每当您更改变量(即,为其分配某些内容)时,您从不修改真实对象。相反,变量开始指向一些不同的对象。

现在,再次查看文档:

遍历聚合类型或数据结构,传递每个 项目到给定的闭包。

就是这样。它为您提供了一个指向每个项目的变量。如果你覆盖了你给定的局部变量,变量开始指向其他对象,就是这样。该列表仍然具有对旧对象的引用。

这些信息是使用 Java 和类似语言进行编程所需的最基本知识。通常在手册/文档的第一页进行解释。而且因为它是基本的,所以没有人会为你有某种参数的每个函数一遍又一遍地解释它。

【讨论】:

  • 突出显示相关文档部分并说明“基本知识”因此没有在所有地方重复提及,这对我来说很清楚。谢谢!
【解决方案2】:

@Max 在上面提供了一个很好的答案。我的 2 美分就可以了。在java中,变量或引用实际上是按值传递。了解这一点也很重要。请注意,对象本身不会被复制,只会复制对它的引用。

现在让我们回到列表。它引用了其中的所有对象。当您在列表中调用each 时,会创建一个指向same 对象的new 引用并传递给each 方法。因此,即使您使这个新创建的引用变量指向不同的对象,列表中的引用仍然保持不变并指向同一个旧对象。

【讨论】:

    猜你喜欢
    • 2019-05-11
    • 2012-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-22
    • 2015-12-31
    相关资源
    最近更新 更多