2009-12-30 8 views
34

Je voudrais utiliser val pour déclarer les variables multiples comme ceci:Déclaration de plusieurs variables Scala

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

Mais pour une raison quelconque, il est une erreur de syntaxe, donc je fini par utiliser soit:

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

ou

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

personnellement, je trouve les deux options trop bavard et un peu laid.

Existe-t-il une meilleure option?

Aussi, je sais que Scala est un langage très bien pensé, alors pourquoi la syntaxe val a = 1, b = 2, c = 3 n'est-elle pas permise?

Répondre

63

La réponse est trivial de les déclarer comme tuples:

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

Ce qui pourrait être intéressant ici est que cela est basé sur la correspondance de motif. Ce qui se passe en réalité, c'est que vous construisez un tuple, puis, par l'intermédiaire de la correspondance de modèle, en affectant des valeurs à a, b et c.

Considérons d'autres exemples de correspondance de modèle pour explorer un peu plus loin:

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" 

Tout comme une note de côté, l'exemple rnd, en particulier, peut être écrit plus simplement, et sans illustrant la recherche de motifs, comme indiqué ci-dessous.

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

Il convient de noter que 'val (a, b, c) = (1, 2, 3)' ne semble être l'expression généralement acceptée pour l'attribution multiple, préférable de séparer les instructions d'affectation. Au moins, cela a été mon impression à travers le code développé par la communauté. –

+16

Il est également intéressant de noter que vous pouvez définir plusieurs vals à la même valeur avec les valeurs intuitives "val x, y, z = 42". –

+2

Il y a aussi 'val seq @ Seq (a, b, c) = Seq (1,2,3)' qui non seulement définit les valeurs 'a',' b' et 'c', mais aussi la seqeunce' seq '! – Mullefa

7

Il semble fonctionner si vous les déclarez dans un tuple

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

Bien que je ne serais probablement aller pour les états individuels. Pour moi, cela semble plus clair:

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

en particulier si les variables sont significativement nommées.

24

La réponse de Daniel résume bien la bonne façon de le faire, ainsi que la raison pour laquelle cela fonctionne. Comme il a déjà couvert cet angle, je vais essayer de répondre à votre question plus large (concernant la conception du langage) ...

Dans la mesure du possible, Scala s'efforce d'éviter d'ajouter des fonctionnalités de langage en faveur de la manipulation des choses à travers les mécanismes existants. Par exemple, Scala n'inclut pas d'instruction break. Cependant, il est presque trivial de rouler un de vos propres comme une bibliothèque:

case object BreakException extends RuntimeException 

def break = throw BreakException 

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

Ceci peut être utilisé de la manière suivante:

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

    // do something normally 
    } 
} 

(Note: ceci est inclus dans la bibliothèque standard pour Scala 2.8)

Les syntaxes d'affectations multiples telles que celles autorisées par des langages tels que Ruby (par exemple x = 1, y = 2, z = 3) entrent dans la catégorie de "syntaxe redondante". Lorsque Scala dispose déjà d'une fonctionnalité qui active un motif particulier, elle évite d'ajouter une nouvelle fonctionnalité uniquement pour gérer un cas particulier de ce modèle. Dans ce cas, Scala a déjà une correspondance de motif (une caractéristique générale) qui peut être utilisée pour gérer plusieurs affectations (en utilisant l'astuce de tuple décrite dans d'autres réponses). Il n'est pas nécessaire de gérer ce cas particulier de manière séparée.

Sur un plan légèrement différent, il convient de noter que la syntaxe d'assignation multiple de C (et donc de Java) est également un cas particulier d'une autre caractéristique plus générale. Tenir compte:

int x = y = z = 1; 

Ce exploite le fait que l'affectation retourne la valeur attribuée dans les langues C-dérivé (ainsi que le fait que la cession est droit associatif). Ce n'est pas le cas chez Scala. Dans Scala, l'affectation renvoie Unit. Bien que cela présente quelques inconvénients gênants, il est plus théoriquement valable car il souligne la nature de l'assignation directement dans son type.

+0

Bonne réponse, je voudrais pouvoir accepter deux réponses = P. – Xavi

+0

Et si je veux déclarer 2 variables mais que je ne veux pas les affecter immédiatement? Comme var a: MyClass, b: MyClass? –

+0

J'espère que vous êtes toujours en train de regarder cette question. 'val x = y = z = 1' fonctionne dans Scala. Il semble être court pour 'val x = 1; val y = 1; val z = 1; 'et pas la même chose que la version C. C'est-à-dire que l'expression à droite de '=' est répliquée et évaluée plusieurs fois. Est-ce ainsi que c'est défini? – RussAbbott

15

J'ajouterai une bizarrerie ici, parce que ça m'a frappé et pourrait aider les autres.

Lors de l'utilisation de l'appariement de motifs, s.a. lors de la déclaration de plusieurs variables, n'utilisez pas de noms de capitale pour les variables. Ils sont traités comme des noms de classes dans la correspondance de modèle, et cela s'applique également ici.

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

message d'erreur ne dit pas vraiment ce qui se passe:

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) 
     ^

Je pensais que `-ticking résoudrait le problème, mais pour une raison quelconque ne semble pas (pas sûr, pourquoi pas):

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

Toujours les mêmes erreurs même avec cela.

Veuillez indiquer si vous savez comment utiliser le modèle d'initialisation de tuple avec des noms de variables de capital.

+3

Je déteste cette «fonctionnalité» de nommage d'identificateur dans Scala. Ce n'est pas grave si vous le savez, mais il continue de trébucher (voir beaucoup d'autres questions) et est complètement déconcertant jusqu'à ce que vous branlez ce qui se passe ... Cela ressemble à "Dieu est réel - à moins d'être déclaré entier" –

+0

Je suis d'accord. Et avec d'autres 'sucre' similaires de Scala. Il serait bon d'avoir un drapeau pour exclure ces raccourcis. Cependant ... mon problème d'origine demeure. Est-il possible d'utiliser les noms de variables CAPITAL avec l'initialisation de tuple? – akauppi

+1

Juste frapper moi-même. Heureusement googling 'scala tuple val val "pas trouvé"' conduit à cette réponse, m'évitant beaucoup de bamboozlement. – timday

4

Si toutes vos variables sont du même type et prennent la même valeur initiale, vous pouvez le faire.

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

Notez que le '0' il y a réellement une fonction. Le remplacer par quelque chose comme Math.random fournit deux valeurs différentes. – akauppi

Questions connexes