2013-02-22 9 views
14

W Pythonie mamy operator gwiazdki (lub "*" lub "rozpakuj"), który pozwala nam rozpakować listę w celu wygodnego użycia w przekazywaniu argumentów pozycyjnych. Na przykład:Czy istnieje odpowiednik Scala dla rozpakowywania listy Pythona (a.k.a. "*")?

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

W tym konkretnym przykładzie, nie zaoszczędzić dużo pisać, ponieważ range trwa tylko dwa argumenty. Ale możesz sobie wyobrazić, że gdyby było więcej argumentów dla range, lub gdyby args został odczytany ze źródła wejściowego, zwrócony z innej funkcji itp., To może się przydać.

W Scali nie udało mi się znaleźć odpowiednika. Rozważmy następujące polecenia uruchamiane w sesji interaktywnej Scala:

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) 

Czy jest bardziej zwięzły sposób to zrobić oprócz metody stosowanej w val y?

+7

Błędnie oznaczono jako duplikat, a nie jest. Scala ma operację ': _ *', ale działa tylko z varargs po stronie definicji: np. 'case class Things (xs: String *)' –

Odpowiedz

4

Jest coś podobnego do funkcji: tupled Konwertuje funkcję, która przenosi n parametrów do funkcji, która przyjmuje jeden argument typu n-tuple.

Zobacz to pytanie, aby uzyskać więcej informacji: scala tuple unpacking

Taka metoda tablic nie miałoby sensu, bo to działa tylko z funkcji z wieloma argumentami samego typu.

+0

Uzgodniono, że nie ma to sensu, ponieważ wszystkie argumenty będą musiały być tego samego typu. W konkretnym przypadku użycia, który rozważam, 'argList' faktycznie będzie pochodził z dzielenia łańcucha dostarczonego jako dane wejściowe, a ja' domyślnie def' niektóre konwersje, aby przekształcić ciągi znaków w te różne typy wymagane przez funkcję, którą próbuję wywołać . Ale nawet wtedy musiałbym zbudować Tupla z Listy, jak przypuszczam. –

+1

Ktoś buduje HList, która jest po prostu listą z niezależnym typem dla każdego elementu. Może być w stanie przekształcić to w krotkę ... Po prostu pomysł. –

+1

@JensSchauder Pomysł, który jest realizowany zarówno przez Scalaz, jak i Shapeless, choć Shapeless zajmuje znacznie więcej. –

18

Nie ma bezpośredniego odpowiednika w scala. Najbliższą rzeczą jest użycie _*, która działa tylko na metodach vararg. Poprzez przykład, tutaj jest przykładem metody vararg:

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

który może być używany z dowolną liczbą argumentów:

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

Teraz, jeśli masz listę ciągów i chcesz przekazać im do tej metody, tak aby go rozpakować jest przez _*:

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

można trochę drogę do Pythonie przy użyciu shapeless,

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

Jak widać, w Scali wymagane jest trochę więcej ceremonii z bezkształtnymi. Dzieje się tak dlatego, że shapeless nakłada ograniczenia czasowe na kompilację, które gwarantują spełnienie w środowisku wykonawczym (w przeciwieństwie do pythona, który zakończy się niepowodzeniem w środowisku wykonawczym, jeśli args ma nieprawidłowy rozmiar lub zawiera elementy niewłaściwego typu) ... zamiast tego jesteś zmuszony określić typ, jakiego oczekuje lista (w tym przypadku dokładnie trzy Strings) i być przygotowanym na obsługę przypadku, w którym to oczekiwanie nie jest spełnione (ponieważ wynikiem jest wyraźnie Option z ThreeValues).

Powiązane problemy