代码之家  ›  专栏  ›  技术社区  ›  jos

在groovy中是否可以突破封闭性?

  •  25
  • jos  · 技术社区  · 17 年前

    有没有一种方法可以“突破”一个groovy闭包?

    可能是这样的:

    [1, 2, 3].each { 
      println(it)
      if (it == 2)
        break 
    }
    
    9 回复  |  直到 8 年前
        1
  •  8
  •   John Wagenleitner    17 年前

    您可以抛出异常:

    try {
        [1, 2, 3].each { 
            println(it)
            if (it == 2)
                throw new Exception("return from closure") 
        }
    } catch (Exception e) { }
    

    使用还可以使用“findall”或“grep”过滤出列表,然后使用“each”。

    [1, 2, 3].findAll{ it < 3 }.each{ println it }
    
        2
  •  21
  •   GreenGiant WoodenKitty    12 年前

    我经常忘记,groovy实现了一个“any”方法。

    [1, 2, 3].any
    {   
       println it
       return (it == 2)
    }​
    
        3
  •  13
  •   Ben Doerr    12 年前

    2013年5月12日重编。

    回答被问到的问题。

    是否有可能打破封闭?

    你会的 “突破” 通过发布 return 关键字。然而,在给出的示例中,这并没有帮助。原因是闭包(将其视为一个方法)是由 each 集合中每个项的方法。

    如果运行此示例,您将看到它将打印1,然后打印3。

    [1, 2, 3].each {
      if (it == 2) return
      println(it)
    }
    

    为什么? break 在 每个 没有道理。

    为了理解为什么你不能突破 每个 方法就像你可以突破 for 循环你需要了解一些实际发生的事情。下面是一个大致的简化,集合中的每个方法都做些什么。

    myEach([0,1,3])
    
    void myEach(List things) {
        for (i in things) {
            myEachMethod(i)
        }
    }
    
    void myEachMethod(Object it) { // this is your Closure
        if(it == 2) return
        println it
    }
    

    正如您所看到的,闭包基本上是一种可以传递的方法。就像Java一样,不能从方法调用或关闭中中断。

    做什么而不是打破 每个 .

    在groovy中,应该使用高级抽象来表示代码,因为这样的原始循环不是惯用的。对于您给出的示例,我将考虑使用findall。例如:

    [1,2,3].findAll { it < 2 }.each { println it }
    

    我希望这能帮助你理解发生了什么。

    回答隐含的问题。

    你能跳出去吗 Collection.each 对你提供的闭包迭代?

    你不能脱离 每个 方法不抛出和捕获异常,如John Wagenleitner所说。尽管我认为以流控制的名义抛出和捕获一个异常是一种代码味道,一个程序员同事可能会拍拍你的手。

        4
  •  8
  •   Community Mohan Dere    9 年前
        5
  •  7
  •   Phat H. VU    12 年前

    尝试使用 任何 而不是 每个

    def list = [1, 2, 3, 4, 5, -1, -2]
    list.any { element ->
        if (element > 3)
        return true // break
        println element
    }
    

    结果是: 1, 2, 3

        6
  •  3
  •   Harry Developer    9 年前

    还有另一种解决方案。尽管如此,像each/find/any这样的绝妙的东西还是很酷的:如果它不适合,就不要使用它。你还是可以用普通的旧的

    for (def element : list)
    

    尤其是,如果你也想离开这个方法。现在您可以随意使用Continue/Break/Return。生成的代码可能并不酷,但很容易理解。

        7
  •  2
  •   Sodastream    15 年前

    这是为了支持约翰·瓦格纳莱特的回答。蒂格里兹的回答显然是错误的。通过执行他的第一个代码示例,或者从理论上阅读groovy文档,可以很容易地证明这一点。一 返回 从当前迭代返回值(或不带参数的空值),但不停止迭代。在一个闭包中,它的行为很像 持续 .

    你将无法使用 注入 不理解这一点。

    除了引发异常之外,无法“中断循环”。为此目的使用异常被认为是臭味。因此,正如wagenleiter所建议的,最佳实践是在启动之前过滤掉您想要迭代的元素。 每个 或者它的一个表亲。

        8
  •  2
  •   sea-kg    12 年前

    只是用特殊的封闭

    // declare and implement:
    def eachWithBreak = { list, Closure c ->
      boolean bBreak = false
      list.each() { it ->
         if (bBreak) return
         bBreak = c(it)
      }
    }
    
    def list = [1,2,3,4,5,6]
    eachWithBreak list, { it ->
      if (it > 3) return true // break 'eachWithBreak'
      println it
      return false // next it
    }
    
        9
  •  0
  •   frhack    11 年前

    用 rx-java 你可以把一个不可测的转化为可观测的。

    那你就可以换了 持续 用一个 滤波器 和 打破 具有 取而代之

    下面是一个例子:

    import rx.Observable
    
    Observable.from(1..100000000000000000)
              .filter { it % 2 != 1} 
              .takeWhile { it<10 } 
              .forEach {println it}