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

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

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

} 

No necesito necesariamente una traducción línea por línea, pero estoy buscando el "modo Scala" para manejar este tipo de problema.¿Cómo se traduce el siguiente código Java "continuar" a Scala?

+1

¿Tiene control sobre la firma del 'getQuote' y' getPrice'? si es así, puede hacer que devuelvan 'Opción [Cotizar]' y 'Opción [Precio]'. – huynhjl

+0

Falta el resto de su "bucle". Actualmente no hace nada. – ziggystar

Respuesta

28

No es necesario continuar o romperse ni nada de eso en casos como este: Opciones y comprensiones para hacer el truco muy bien,

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

Generalmente se intenta evitar esas situaciones, para empezar filtrando incluso antes de empezar:

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

(este ejemplo que muestra cómo te llevas resultados parciales si los necesita) Utilicé una vista para que los resultados se computen según sea necesario, en lugar de crear un conjunto de colecciones nuevas en cada paso.

En realidad, probablemente tenga las comillas y esas opciones de devolución: mire en StackOverflow para ver ejemplos de cómo usarlos en lugar de valores de devolución nulos.

Pero, de todos modos, si ese tipo de cosas no funciona tan bien (por ejemplo, porque está generando demasiados resultados intermedios que debe conservar, o depende de la actualización de variables variables y desea mantener la evaluación patrón simple para que sepa lo que está sucediendo cuando) y no se puede concebir el problema de una manera diferente, posiblemente más robusto, entonces se puede

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

la construcción breakable especifica dónde se rompe es ir a. Si coloca el breakable fuera de un bucle for, funciona como un corte estándar de Java. Si lo pones adentro, actúa como continue.

Por supuesto, si tiene un número muy pequeño de condiciones, no necesita continuar; solo usa el else del enunciado if.

+0

¿Esto significaría que se debe llamar a getQuote dos veces para todas las coincidencias válidas? – deltanovember

+0

@deltanovember - ¿Ves alguna repetición de 'getQuote' en mi código de ejemplo? El valor está almacenado; es por eso que hay un mapa _primero_ y luego un filtro. –

+2

Su filtro es realmente mucho más complicado de lo necesario, y no hay absolutamente ninguna necesidad de usar el que se pueda romper en la versión de comprensión. –

3

Si la atención se centra realmente en el continue y no en el manejo null, simplemente definir un método interior (la parte de manipulación null es un idioma diferente en 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

Su estructura de control que aquí puede haber mapeado muy idiomáticamente en el siguiente loop for, y su código demuestra el tipo de filtrado para el que se diseñó el bucle for de Scala.

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

Por cierto, Scala desugar automáticamente esto en el código de la solución de Rex Kerr

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

Esta solución probablemente no funciona en general para todos los diferentes tipos de flujos más complejos que podrían utilizar continue, pero aborda muchos de los más comunes.

+0

El método de aplicación del objeto complementario de la opción hará la comprobación nula por usted: reemplace la verificación nula explícita en su variante con la opción () y terminará con la mía. –

+0

@Miles: eso es ciertamente correcto, pero no muestra los filtros 'si' que probablemente quiere saber el autor de la pregunta, y usted tiene que explicar lo que hace el constructor 'Opción'. –

+0

No estoy tan seguro ... me parece que tiene una instancia clásica de un problema que tiene una solución monádica mejor que una que implica condicionales. Sí, hubo condicionales en la pregunta, pero las implicaciones fueron que el interrogador no pensó que el uso fuera idiomático ... y estoy de acuerdo ;-) –

Cuestiones relacionadas