2009-12-30 22 views
34

me gustaría utilizar val declarar múltiples variables como esto:Declarar múltiples variables en Scala

val a = 1, b = 2, c = 3 

Pero por alguna razón, se trata de un error de sintaxis, por lo que terminó utilizando:

val a = 1 
val b = 2 
val c = 3 

o

val a = 1; val b = 2; val c = 3; 

personalmente encuentro ambas opciones excesivamente prolijo y un poco feo.

¿Existe una opción mejor?

Además, sé que Scala es un lenguaje muy bien pensado, ¿por qué no se permite la sintaxis val a = 1, b = 2, c = 3?

Respuesta

63

La respuesta trivial es declarar como tuplas:

val (a, b, c) = (1, 2, 3) 

¿Cuál podría ser interesante aquí es que esto se basa en la coincidencia de patrones. Lo que sucede en realidad es que está construyendo una tupla y luego, mediante la coincidencia de patrones, asigna valores a a, b y c.

Vamos a considerar algunos otros ejemplos coincidencia de patrones para explorar esto un poco más lejos:

val DatePattern = """(\d{4})-(\d\d)-(\d\d)""".r 
val DatePattern(year, month, day) = "2009-12-30" 
val List(rnd1, rnd2, rnd3) = List.fill(3)(scala.util.Random.nextInt(100)) 
val head :: tail = List.range(1, 10) 

object ToInt { 
    def unapply(s: String) = try { 
    Some(s.toInt) 
    } catch { 
    case _ => None 
    } 
} 

val DatePattern(ToInt(year), ToInt(month), ToInt(day)) = "2010-01-01" 

Así como una nota al margen, el ejemplo rnd, en particular, puede ser escrito más simplemente, y sin detenerse en concordancia con el modelo, Como se muestra abajo.

val rnd1, rnd2, rnd3 = scala.util.Random.nextInt(100) 
+2

Vale la pena señalar que 'val (a, b, c) = (1, 2, 3)' no parece ser el idioma generalmente aceptada para la asignación múltiple, preferible separar instrucciones de asignación. Al menos, esa ha sido mi impresión al leer el código desarrollado por la comunidad. –

+16

También vale la pena señalar que puede establecer valores múltiples en el mismo valor con el "val x, y, z = 42" intuitivo. –

+2

También hay 'val seq @ Seq (a, b, c) = Seq (1,2,3)' que no solo define los valores 'a',' b' y 'c', sino también el seqeunce' seq '! – Mullefa

7

parece que funciona si se declaran en una tupla

scala> val (y, z, e) = (1, 2, 45) 
y: Int = 1 
z: Int = 2 
e: Int = 45 
scala> e 
res1: Int = 45 

Aunque probablemente me iría para los estados individuales. Para mí esto se ve más claro:

val y = 1 
val z = 2 
val e = 45 

especialmente si las variables se denominan de manera significativa.

24

respuesta de Daniel resume muy bien la forma correcta de hacer esto, así como por qué funciona. Como él ya cubrió ese ángulo, intentaré responder a su pregunta más amplia (con respecto al diseño del idioma) ...

Siempre que sea posible, Scala se esfuerza por evitar agregar funciones de idioma a los mecanismos existentes. Por ejemplo, Scala no incluye una declaración break. Sin embargo, es casi trivial para rodar una de su propio como una biblioteca:

case object BreakException extends RuntimeException 

def break = throw BreakException 

def breakable(body: =>Unit) = try { 
    body 
} catch { 
    case BreakException =>() 
} 

Esto se puede utilizar de la siguiente manera:

breakable { 
    while (true) { 
    if (atTheEnd) { 
     break 
    } 

    // do something normally 
    } 
} 

(nota: esto está incluido en la biblioteca estándar para Scala 2.8)

Las sintaxis de asignaciones múltiples, como las permitidas por los idiomas como Ruby (por ejemplo, x = 1, y = 2, z = 3) entran en la categoría de "sintaxis redundante". Cuando Scala ya tiene una característica que habilita un patrón particular, evita agregar una nueva característica solo para manejar un caso especial de ese patrón. En este caso, Scala ya tiene una coincidencia de patrones (una característica general) que se puede usar para manejar asignaciones múltiples (mediante el truco de tupla descrito en otras respuestas). No es necesario que maneje ese caso especial en particular de forma separada.

En un lado ligeramente diferente, cabe señalar que la sintaxis de asignación múltiple de C (y, por lo tanto, Java) también es un caso especial de otra característica más general. Considerar:

int x = y = z = 1; 

Este explota el hecho de que la asignación devuelve el valor asignado en lenguajes C-derivado (así como el hecho de que la asignación es asociativo por la derecha). Este no es el caso en Scala. En Scala, la asignación devuelve Unit. Si bien esto tiene algunos inconvenientes molestos, es más teóricamente válido ya que enfatiza la naturaleza de la asignación colateral de la asignación directamente en su tipo.

+0

Gran respuesta, desearía poder aceptar dos respuestas = P. – Xavi

+0

¿Qué pasa si quiero declarar 2 variables pero no quiero asignarlas inmediatamente? Como var a: MyClass, b: MyClass? –

+0

Espero que sigas viendo esta pregunta. 'val x = y = z = 1' funciona en Scala. Parece ser breve para 'val x = 1; val y = 1; val z = 1; 'y no es lo mismo que la versión C. Es decir, la expresión a la derecha de '=' se replica y evalúa varias veces. ¿Es así como se define? – RussAbbott

15

Agregaré una peculiaridad aquí, porque me golpeo y podría ayudar a otros.

Al usar la coincidencia de patrones, por ejemplo al declarar múltiples variables, no use los nombres de Capital para las variables. Se tratan como nombres de clases en la coincidencia de patrones, y se aplica aquí también.

val (A,B)= (10,20) // won't work 
    println(A) 

mensaje de error realmente no dice lo que está pasando:

src/xxx.scala:6: error: not found: value A 
    val (A,B)= (10,20) 
    ^
src/xxx.scala:6: error: not found: value B 
    val (A,B)= (10,20) 
     ^
src/xxx.scala:7: error: not found: value A 
    println(A) 
     ^

pensé `-ticking resolvería el problema, pero por alguna razón no parece (no estoy seguro, ¿por qué no):

val (`A`,`B`)= (10,20) 
    println(A) 

Todavía los mismos errores incluso con eso.

Comente si sabe cómo utilizar el patrón de inicialización de tupla con nombres de variable de capital.

+3

Detesto esa 'característica' de identificar nomenclatura en Scala. Está bien si lo sabes, pero sigue sorprendiendo a la gente (ver muchas otras preguntas) y es completamente desconcertante hasta que entiendes lo que está pasando ... Huele a "Dios es real, a menos que se declare entero" de Fortan –

+0

Estoy de acuerdo. Y con otro 'azúcar' similar de Scala. Sería bueno tener una bandera para descartar tales atajos. Sin embargo ... mi problema original aún permanece. ¿Hay alguna forma de usar nombres de variable CAPITAL con inicialización de tupla? – akauppi

+1

Solo presiona esto yo mismo. Afortunadamente, googlear 'scala tuple assignment val' no encontrado '' condujo a esta respuesta, evitándome mucho alboroto. – timday

4

Si todas sus variables son del mismo tipo y toman el mismo valor inicial, puede hacerlo.

val a, b, c: Int = 0; 
+3

Tenga en cuenta que el '0' en realidad es una función. Sustituirlo por algo como Math.random proporciona dos valores diferentes. – akauppi

Cuestiones relacionadas