看来,Groovy的不支持break
,并continue
从封闭中。模拟此的最佳方法是什么?
revs.eachLine { line ->
if (line ==~ /-{28}/) {
// continue to next line...
}
}
Answers:
您只能支持继续干净地进行,不能中断。特别是像eachLine和each这样的东西。无法支持中断与那些方法的评估方式有关,没有考虑未完成可以传达给该方法的循环。这是继续支持的方法-
最佳方法(假设您不需要结果值)。
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。
闭包不能中断或继续,因为它们不是循环/迭代构造。相反,它们是用于处理/解释/处理迭代逻辑的工具。您可以通过简单地从闭包中返回而不进行如下处理来忽略给定的迭代:
revs.eachLine { line ->
if (line ==~ /-{28}/) {
return
}
}
中断支持不会在闭包级别发生,而是由接受闭包的方法调用的语义所隐含。简而言之,这意味着您不必调用像集合这样的用于处理整个集合的东西上的“每个”,而应该调用find,它将一直处理到满足特定条件为止。大多数(所有?)时间,您觉得需要从闭合中打破,您真正想做的是在迭代过程中找到特定条件,这使find方法不仅符合您的逻辑需求,而且符合您的意图。遗憾的是,某些API缺少对find方法的支持...例如文件。可能所有花费在争论该语言是否应包含中断/继续上的时间都可以很好地用于向这些被忽略的区域添加查找方法。诸如firstDirMatching(Closure c)或findLineMatching(Closure c)之类的东西会走很长一段路,并回答99%以上的“我为什么不能摆脱……?”的问题。在邮件列表中弹出的问题。也就是说,自己通过MetaClass或Categories添加这些方法很简单。
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}/ }
涉及异常和其他魔术的其他黑客可能会起作用,但在某些情况下会带来额外的开销,而在其他情况下会混淆可读性。真正的答案是查看您的代码,然后询问您是否真正在迭代或搜索。
如果您使用Java预创建了一个静态Exception对象,然后从闭包内部抛出了(静态)异常,则运行时的成本将降至最低。实际成本是在创建异常而不是引发异常时产生的。根据Scala的发明者Martin Odersky的说法,许多JVM实际上可以优化单跳的抛出指令。
这可以用于模拟中断:
final static BREAK = new Exception();
//...
try {
... { throw BREAK; }
} catch (Exception ex) { /* ignored */ }
使用回归到继续和任何封闭到打破。
例
档案内容:
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"
我想那会更清楚