当前位置:  开发笔记 > 编程语言 > 正文

在Groovy闭包中模拟"继续"的最佳模式

如何解决《在Groovy闭包中模拟"继续"的最佳模式》经验,为你挑选了4个好方法。

看来,Groovy的不支持break,并continue从封闭中.模拟这个的最佳方法是什么?

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
         // continue to next line...
    }
}

shemnon.. 71

你只能支持干净,而不是休息.特别是像每条线和每条线的东西.无法支持中断与如何评估这些方法有关,没有考虑不完成可以传递给方法的循环.以下是如何继续支持 -

最佳方法(假设您不需要结果值).

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
        return // returns from the closure
    }
}

如果您的样本真的那么简单,那么这对于可读性是有好处的.

revs.eachLine { line -> 
    if (!(line ==~ /-{28}/)) {
        // do what you would normally do
    }
}

另一种选择,模拟继续在字节码级别通常会做什么.

revs.eachLine { line -> 
    while (true) {
        if (line ==~ /-{28}/) {
            break
        }
        // rest of normal code
        break
    }

}

支持休息的一种可能方法是通过例外:

try {
    revs.eachLine { line -> 
        if (line ==~ /-{28}/) {
            throw new Exception("Break")
        }
    }
} catch (Exception e) { } // just drop the exception

您可能希望使用自定义异常类型来避免屏蔽其他实际异常,特别是如果您在该类中进行其他可能会抛出实际异常的处理,例如NumberFormatExceptions或IOExceptions.



1> shemnon..:

你只能支持干净,而不是休息.特别是像每条线和每条线的东西.无法支持中断与如何评估这些方法有关,没有考虑不完成可以传递给方法的循环.以下是如何继续支持 -

最佳方法(假设您不需要结果值).

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
        return // returns from the closure
    }
}

如果您的样本真的那么简单,那么这对于可读性是有好处的.

revs.eachLine { line -> 
    if (!(line ==~ /-{28}/)) {
        // do what you would normally do
    }
}

另一种选择,模拟继续在字节码级别通常会做什么.

revs.eachLine { line -> 
    while (true) {
        if (line ==~ /-{28}/) {
            break
        }
        // rest of normal code
        break
    }

}

支持休息的一种可能方法是通过例外:

try {
    revs.eachLine { line -> 
        if (line ==~ /-{28}/) {
            throw new Exception("Break")
        }
    }
} catch (Exception e) { } // just drop the exception

您可能希望使用自定义异常类型来避免屏蔽其他实际异常,特别是如果您在该类中进行其他可能会抛出实际异常的处理,例如NumberFormatExceptions或IOExceptions.


使用异常来控制程序流是一个坏主意.创建异常需要拍摄调用堆栈的快照,这样做成本很高.
如果您使用闭包而不是将其视为循环结构,那么这也是努力解决您不会遇到的问题的额外步骤.上述示例将从将逻辑的不明确的整体意图固定到过滤行或找到一行来获益更多.
如果您在异常中重写生成调用堆栈的方法,则不会执行任何操作.这是自定义异常的优势.

2> Cliff..:

闭包不能中断或继续,因为它们不是循环/迭代构造.相反,它们是用于处理/解释/处理迭代逻辑的工具.您可以通过简单地从闭包返回而无需处理来忽略给定的迭代:

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
            return
    }

}

中断支持不会在闭包级别发生,而是由接受闭包的方法调用的语义隐含.简而言之,这意味着不是在像集合那样处理整个集合的东西上调用"each",而应该调用find,它将处理直到满足某个条件.大多数(全部?)次你觉得需要从闭包中断开你真正想要做的是在迭代期间找到一个特定的条件,这使得find方法不仅符合你的逻辑需求而且符合你的意图.遗憾的是,一些API缺乏对find方法的支持......例如File.有可能所有的时间花在争论语言中应该包括break/continue,这可能会花费很多时间将find方法添加到这些被忽视的区域.像firstDirMatching(Closure c)或findLineMatching(Closure c)之类的东西会走很长的路,回答99%以上的"为什么我不能从...中断?" 邮件列表中弹出的问题.也就是说,通过MetaClass或类别自己添加这些方法是微不足道的.

class FileSupport {
   public static String findLineMatching(File f, Closure c) {
      f.withInputStream {
         def r = new BufferedReader(new InputStreamReader(it))
         for(def l = r.readLine(); null!=l; l = r.readLine())
             if(c.call(l)) return l
         return null
      }
   }
}

using(FileSupport) { new File("/home/me/some.txt").findLineMatching { line ==~ /-{28}/ }

其他涉及异常和其他魔法的黑客可能会起作用,但在某些情况下会引入额外的开销,并且在其他情况下会产生可读性.真正的答案是查看您的代码并询问您是否真的在迭代或搜索.



3> Ralph..:

如果在Java中预先创建一个静态Exception对象,然后从闭包内抛出(静态)异常,则运行时成本最小.创建异常会产生实际成本,而不是抛出异常.根据Martin Odersky(Scala的发明者)的说法,许多JVM实际上可以优化单指令跳转指令.

这可以用来模拟休息:

final static BREAK = new Exception();
//...
try {
  ... { throw BREAK; }
} catch (Exception ex) { /* ignored */ }


那...这是一个非常好的想法.将其与枚举相结合,为每个枚举构建一个预先创建的异常.哎呀 - 把一个方法放在枚举中抛出它.Condition.BAD_WEATHER.fire();

4> Michal Z m u..:

使用回归继续任何封闭到打破.

文件内容:

1
2
----------------------------
3
4
5

Groovy代码:

new FileReader('myfile.txt').any { line ->
    if (line =~ /-+/)
        return // continue

    println line

    if (line == "3")
        true // break
}

输出:

1
2
3


如果您仅用`line ==“ 3”`替换最后一个if块,我认为它会更清晰一些
推荐阅读
Chloemw
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有