25

Nur um zu klären, wenn ich mehrere assigment, parallel Zuordnung sagen, bind Destrukturierung I folgende Bedeutung Musteranpassungs gemMehrfachzuordnung von nicht-Tupeln in Scala

scala> val (x,y) = Tuple2("one",1) 
x: java.lang.String = one 
y: Int = 1 

die "one" zu x und 1 zu y zuordnet.

ich versuche

val (x,y) = "a b".split() 

ich, dass scala erwarte zu tun versuchen würde, das Array mit dem Muster zu Mustern entspricht, und würde eine Laufzeit Ausnahme auslösen, wenn die Länge des Arrays nicht die Länge entsprechen würde des Musters.

Alle meine Versuche, eine Array in eine Tuple2 zu konvertieren, waren sinnlos.

scala> Tuple2(Array(1,2):_*) 
<console>:7: error: wrong number of arguments for method apply: (T1,T2)(T1, T2) 
in object Tuple2 
     Tuple2(Array(1,2):_*) 
    ^

scala> Tuple2(Array(1,2).toList:_*) 
<console>:7: error: wrong number of arguments for method apply: (T1,T2)(T1, T2) 
in object Tuple2 
     Tuple2(Array(1,2).toList:_*) 

Gibt es eine nette Möglichkeit, Mehrfachzuweisungen mit Arrays oder Listen zu verwenden?

Antwort

43

Alles, was Sie tun müssen, ist Ihre val Seite zu machen (links von der =) kompatibel mit Ihrem initializer (rechts neben der =):

scala> val Array(x, y, z) = "XXX,YYY,ZZZ".split(",") 
x: java.lang.String = XXX 
y: java.lang.String = YYY 
z: java.lang.String = ZZZ 

Wie Sie erwartet, wird ein scala.MatchError geworfen werden zur Laufzeit, wenn die Array-Größe nicht übereinstimmt (im obigen Beispiel nicht 3).

+9

Dies funktioniert, weil das Objekt 'Array' die 'unapplySeq'-Methode enthält, wodurch es als Extraktor-Muster verwendbar ist. 'Array.unapplySeq (" XXX, YYY, ZZZ ".split (", ")' wird aufgerufen und gibt 'Some (ArrayBuffer (XXX, YYY, ZZZ))' zurück, was ein 'Some' ist und drei Elemente enthält Binde an 'x',' y' und 'z'. – retronym

12

Da Ihre Zeichenfolge beliebige Inhalte haben kann, kann das Ergebnis keine 2-Tupel-Form durch das Typsystem garantieren (und keine Konvertierung wäre überhaupt sinnvoll). Daher müssen Sie sich mit Sequenzen (wie Arrays) sowieso befassen.

Zum Glück gibt es right-ignoring sequence patterns, mit denen Sie die Ergebniswerte bequem dennoch anpassen können.

val Seq(x, y, _ @ _*) = "a b".split(" ") 
+0

mich Zitiert: „Ich, dass scala das Array mit dem Muster zu Muster passen würde versuchen, erwartete, und würde eine Laufzeitausnahme, wenn die Länge des Arrays der Länge des Musters entsprechen würde nicht werfen“, auch siehe Randalls Lösung. Wie auch immer, das ist auch eine nette Sache. So einfach, ich wünschte, ich hätte selbst darüber nachgedacht. +1. –

+0

In Scala 2.8 ist Array nicht mehr Seq, daher funktioniert diese Technik dort nicht. –

+1

Die Technik funktioniert sicherlich, Sie schreiben einfach "Array" statt "Seq". Oder wenn Sie über das Ende des Strings chillen können, val Array (x, y) = "ab" split "" nehmen 2 – extempore

6
 
scala> val Array(x, y, _*) = "a b" split " " 
x: java.lang.String = a 
y: java.lang.String = b