2013-02-22 11 views
14

In Python haben wir den Stern (oder "*" oder "entpacken") -Operator, der es uns erlaubt, eine Liste zu entpacken, um bequem Positionsargumente zu übergeben. Zum Beispiel:Gibt es ein Scala-Äquivalent des Python-Listen-Entpackers (a.k.a.. "*")?

range(3, 6) 
args = [3, 6] 
# invokes range(3, 6) 
range(*args) 

In diesem speziellen Beispiel ist es nicht viel Tipparbeit sparen, da range nur zwei Argumente übernimmt. Aber Sie können sich vorstellen, dass, wenn es mehr Argumente zu range gäbe, oder wenn args von einer Eingabequelle gelesen wurde, von einer anderen Funktion, etc. zurückgegeben wurde, dann könnte dies nützlich sein.

In Scala konnte ich kein Äquivalent finden. Betrachten Sie die folgenden Befehle in einer Scala interaktiven Sitzung ausführen:

case class ThreeValues(one: String, two: String, three: String) 

//works fine 
val x = ThreeValues("1","2","3") 

val argList = List("one","two","three") 

//also works 
val y = ThreeValues(argList(0), argList(1), argList(2)) 

//doesn't work, obviously 
val z = ThreeValues(*argList) 

Gibt es eine prägnante Art und Weise dies in val y verwendet neben dem Verfahren zu tun?

+7

Wird fälschlicherweise als Duplikat markiert, während dies nicht der Fall ist. Scala hat ': _ * 'Operation, aber es funktioniert nur mit Varargs auf der Definitionsseite: z. 'case class Things (xs: String *)' –

Antwort

4

Es gibt etwas Ähnliches für Funktionen: tupled Es konvertiert eine Funktion, die n Parameter in eine Funktion, die ein Argument vom Typ n-Tupel dauert.

Sehen Sie diese Frage für weitere Informationen: scala tuple unpacking

Ein solches Verfahren für Arrays würde nicht viel Sinn machen, weil es nur mit Funktionen mit mehreren Argumenten gleichen Typs funktionieren würde.

+0

Einverstanden, dass es keinen Sinn ergeben würde, wenn alle Argumente den gleichen Typ hätten. In dem speziellen Anwendungsfall, den ich in Betracht ziehe, wird "argList" tatsächlich von der Aufspaltung einer als Eingabe bereitgestellten Zeichenkette kommen, und ich würde "implizit def" einige Umwandlungen machen, um Strings in die verschiedenen Typen umzuwandeln, die von der Funktion, die ich aufrufen möchte, benötigt werden . Aber selbst dann müsste ich ein Tuple aus einer Liste bauen, nehme ich an. –

+1

Jemand erstellt einen HList, was im Grunde eine Liste mit einem unabhängigen Typ für jedes Element ist. Könnte in der Lage sein, dies in ein Tupel zu konvertieren ... Nur eine Idee. –

+1

@JensSchauder Eine Idee, die sowohl von Scalaz als auch von Shapeless umgesetzt wird, obwohl Shapeless noch viel weiter geht. –

18

Es gibt keine direkte Entsprechung in scala. Das nächste, was Sie finden, ist die Verwendung von _*, die nur mit Vararg-Methoden funktioniert. Durch Beispiel, hier ist ein Beispiel für eine Vararg Methode:

def hello(names: String*) { 
    println("Hello " + names.mkString(" and ")) 
} 

, die mit einer beliebigen Anzahl von Argumenten verwendet werden können:

scala> hello() 
Hello 
scala> hello("elwood") 
Hello elwood 
scala> hello("elwood", "jake") 
Hello elwood and jake 

Nun, wenn Sie eine Liste von Strings und wollen passieren sie zu dieser Methode, so, wie es zu entpacken ist durch _*:

scala> val names = List("john", "paul", "george", "ringo") 
names: List[String] = List(john, paul, george, ringo) 
scala> hello(names: _*) 
Hello john and paul and george and ringo  
4

Sie können einen Weg in Richtung der Python erhalten shapeless verwenden,

Welcome to Scala version 2.11.0-20130208-073607-ce32c1af46 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_05). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> import shapeless._ 
import shapeless._ 

scala> import Traversables._ 
import Traversables._ 

scala> case class ThreeValues(one: String, two: String, three: String) 
defined class ThreeValues 

scala> val argList = List("one","two","three") 
argList: List[String] = List(one, two, three) 

scala> argList.toHList[String :: String :: String :: HNil].map(_.tupled).map(ThreeValues.tupled) 
res0: Option[ThreeValues] = Some(ThreeValues(one,two,three)) 

Wie Sie sehen können, ist ein wenig mehr Zeremonie in Scala mit formlos erforderlich. Der Grund dafür ist, dass formlos Beschränkungen der Kompilierzeit auferlegt, die garantiert zur Laufzeit erfüllt sind (im Gegensatz zum Python, das zur Laufzeit fehlschlägt, wenn args die falsche Größe hat oder Elemente des falschen Typs enthält) ... stattdessen müssen Sie angeben den Typ, den Sie von der Liste erwarten (in diesem Fall genau drei Strings) und bereit sein, den Fall zu behandeln, in dem diese Erwartung nicht erfüllt ist (weil das Ergebnis explizit ein Option von ThreeValues ist).

Verwandte Themen