2011-07-17 32 views
15
for (String stock : allStocks) { 

    Quote quote = getQuote(...); 
    if (null == quoteLast) { 
     continue; 
    } 

    Price price = quote.getPrice(); 
    if (null == price) { 
     continue; 
    } 

} 

我不一定需要一行一行的翻译,但我正在寻找“斯卡拉方式”来处理这类问题。以下Java“继续”代码如何转换为Scala?

+1

你有控制getQuote'和'签名' getPrice'?如果是的话,你可以让他们返回'Option [Quote]'和'Option [Price]'。 – huynhjl

+0

你的“循环”的其余部分缺失。目前它什么都不做。 – ziggystar

回答

28

你不需要继续或容易破裂或类似的东西,在这样的情况下:选项和内涵做的伎俩非常漂亮,

val stocksWithPrices = 
    for { 
    stock <- allStocks 
    quote <- Option(getQuote(...)) 
    price <- Option(quote.getPrice()) 
    } yield (stock, quote, price); 
9

一般尽量避免这些情况通过过滤先跟你甚至开始之前:

val goodStocks = allStocks.view. 
    map(stock => (stock, stock.getQuote)).filter(_._2 != null). 
    map { case (stock, quote) => (stock,quote, quote.getPrice) }.filter(_._3 != null) 

(这个例子显示你如何沿部分结果进行,如果你需要他们)。我使用了一个视图,以便根据需要计算结果,而不是在每个步骤创建一堆新的集合。

实际上,您可能会有引号和返回选项 - 在StackOverflow中查看如何使用这些代替空返回值的示例。但是,无论如何,如果这种事情不能很好地发挥作用(例如,因为你产生了太多的中间结果,你需要保留,或者你依赖更新可变变量,并且你想保持评估图案简单,所以你知道发生了什么的时候),你不能在一个不同的,可能更健壮的方式受孕的问题,那么你可以

import scala.util.control.Breaks._ 
for (stock <- allStocks) { 
    breakable { 
    val quote = getQuote(...) 
    if (quoteLast eq null) break; 
    ... 
    } 
} 

breakable结构指定地方休息应该带你去。如果你在for循环之外放置breakable,它就像一个标准的Java风格的break。如果你把它放在里面,它就像continue一样。

当然,如果你有很少的条件,你根本不需要继续;只需使用if语句的else。

+0

这是否意味着getQuote必须在所有有效匹配中调用两次? – deltanovember

+0

@deltanovember - 您是否在我的示例代码中看到任何重复的getQuote?该值被存储;这就是为什么有一张地图_first_然后是一个过滤器。 –

+2

你的过滤器实际上比必要的复杂得多,并且绝对不需要在理解版本中使用易碎。 –

3

如果焦点是真的就continue而不是在null处理,只是限定了内部方法(null处理部分是Scala中的一个不同的成语):

def handleStock(stock: String): Unit { 
    val quote = getQuote(...) 
    if (null == quoteLast) { 
    return 
    } 

    val price = quote.getPrice(); 
    if (null == price) { 
    return 
    } 
} 

for (stock <- allStocks) { 
    handleStock(stock) 
} 
7

在这里你的控制结构可非常地道地映射到以下for循环中,并且您的代码演示了Scala的for循环所针对的过滤类型。

for {stock <- allStocks.view 
    quote = getQuote(...) 
    if quoteLast != null 
    price = quote.getPrice 
    if null != price 
    }{ 
     // whatever comes after all of the null tests 
    } 

顺便说一句,斯卡拉将自动desugar到雷克斯·科尔的解决方案

val goodStocks = allStocks.view. 
    map(stock => (stock, stock.getQuote)).filter(_._2 != null). 
    map { case (stock, quote) => (stock,quote, quote.getPrice) }.filter(_._3 != null) 

代码本该解决方案可能不会在一般的工作,对各种不同类型的更复杂的流程可能使用的continue,但它确实解决了很多常见问题。

+0

Option的伴随对象的apply方法将为您执行空值检查:使用Option()替换您的变体中的显式空值检查,您将最终与我的。 –

+0

@Miles:这当然是正确的,但它并没有展示提问者可能想要了解的if过滤器,而且你必须解释'Option'构造函数的作用。 –

+0

我不太确定......它看起来像他有一个问题的经典实例,它有一个比涉及条件的更好的monadic解决方案。是的,这个问题中有条件限制,但其含义是提问者不认为用法是惯用的......并且我同意;-) –