2013-03-29 18 views
9

Czy istnieje sposób na częściowe dopasowanie do tuple bez konieczności określania rozmiaru? Na przykład, gdybym miał krotkiDopasuj krotkę o nieznanym rozmiarze w scala

val v = ("Dr", "John","H", "Watson") 

Chciałbym móc zrobić coś takiego:

v match { 
    case ("Dr", : _*) => "What's up, Doc?" 
    case ("Mr", name, :_*) => s"Welcome, Mr. ${name}" 
    case _ => "Have we met?" 
} 

To nie kompiluje, :_* zwykle oznacza nieokreślonej liczby parametrów, ale nie może być w tym przypadku najwyraźniej zastosowany. Pomysł polegałby na tym, aby móc użyć tego narzędzia matującego dla każdej krotki większej niż 2. Wiem, że mogę to zrobić, konwertując najpierw v na List (na przykład), chcę tylko wiedzieć, czy można to zrobić za pomocą tuple.

EDIT: najbardziej informacji znalazłem w internecie jest this discussion, który sięga Scala 2.8, więc będę z „Nie, nie można” odpowiedź.

+0

O ile mi wiadomo, nie ma mowy, ponieważ krotki o różnych rozmiarach są różnymi typami. Ale można to zrobić za pomocą makr - celem jest wygenerowanie kodu, który będzie pasował do wszystkich możliwych rozmiarów. Lub zgodnie z sugestią, określ niejawne konwersje na 'Seq [Any]'. To też jest brudne rozwiązanie i lepiej zadać sobie pytanie, czy krotki są właściwym typem do zastosowania w twoim problemie? Może nie są. –

+1

@SargeBorsch, ale wszystkie one rozszerzają Produkt ;-) –

+0

@ om-nom-nom Tak, to prawda, ale jeśli masz typ Product, nie znasz typów jego elementów i tym samym tracisz bezpieczny dostęp do swoich danych (potrzebujesz ręcznie sprawdzać/odlewać typy jego elementów) –

Odpowiedz

11

Krotki są strukturami heterogenicznych typów. Jako takie, realizują one cechę productIterator, więc można zrobić:

v.productIterator.toList match { 
    case "Dr" :: _ => "What's up, Doc?" 
    case "Mr" :: name :: _ => s"Welcome, Mr. ${name}" 
    case _ => "Have we met?" 
} 

Ale twój przykład naprawdę wygląda chcesz Seq[String] razu. Czy jest jakiś powód, dla którego chciałbyś użyć krotek?

+1

Jak stwierdzono w pytaniu, chcę tylko wiedzieć, czy jest to możliwe, nie ma specjalnego powodu, aby używać krotek. Właściwie to wcale nie muszę tego robić, po prostu będąc ciekawym: D – Chirlo

+1

Krótka odpowiedź brzmi "nie", krotki różnych aranżów nic wśród nich nie dzielą, poza zapewnieniem "Iteratora [Any]". –

10

Można to zrobić za pomocą shapeless „s konwersji z krotek do HLists,

scala> import shapeless._ 
import shapeless._ 

scala> import Tuples._ 
import Tuples._ 

scala> val v = ("Dr", "John","H", "Watson") 
v: (String, String, String, String) = (Dr,John,H,Watson) 

scala> v.hlisted match { 
    | case "Dr" :: _ => "What's up Doc?" 
    | case "Mr" :: name :: _ => s"Welcome, Mr. ${name}" 
    | case _ => "Have we met?" 
    | } 
res0: String = What's up Doc? 

Chociaż nie jest to widoczne w powyższym przykładzie, należy pamiętać, że w miarę możliwości pełny statyczna informacja typu utrzymuje się nazwami związany w klauzule przypadku, na przykład,

scala> (23, "foo", true).hlisted match { 
    | case i :: s :: b :: HNil => if(b) i+s.length else 0 
    | case _ => -1 
    | } 
res1: Int = 26 
-1

Spróbuj tego:

case tuple:Product => { 
    tuple.productIterator.toList match { 
     case (head::rest) => ... 

    } 
}